我有一种情况需要生成一个带有大字符串const的类.我控制之外的代码导致我生成的CodeDom树被发送到C#源,然后被编译为更大的Assembly的一部分.
不幸的是,我遇到这种情况,如果这个字符串的长度超过Win2K8 x64中的335440个字符(Win2K3 x86中的926240),则C#编译器会以致命错误退出:
MSDN称CS1647是"编译器中的堆栈溢出"(没有双关语!).仔细观察我已经确定CodeDom"很好地"将我的字符串const包装在80个字符处.这导致编译器连接4193个字符串块,这显然是x64 NetFx中C#编译器的堆栈深度.CSC.exe必须在内部递归计算此表达式以"重新水化"我的单个字符串.
我最初的问题是:"有没有人知道改变代码生成器如何发出字符串的解决办法? "我无法控制外部系统使用C#source作为中间件的事实,我希望这是一个常量(而不是而不是字符串的运行时串联).
或者,我该怎么制定这个表达式使得一定数量的字符后,我仍然能够创造一个恒定的,但它是由多个的大型块?
完整的repro在这里:
// this string breaks CSC: 335440 is Win2K8 x64 max, 926240 is Win2K3 x86 max
string HugeString = new String('X', 926300);
CodeDomProvider provider = CodeDomProvider.CreateProvider("C#");
CodeCompileUnit code = new CodeCompileUnit();
// namespace Foo {}
CodeNamespace ns = new CodeNamespace("Foo");
code.Namespaces.Add(ns);
// public class Bar {}
CodeTypeDeclaration type = new CodeTypeDeclaration();
type.IsClass = true;
type.Name = "Bar";
type.Attributes = MemberAttributes.Public;
ns.Types.Add(type);
// public const string HugeString …Run Code Online (Sandbox Code Playgroud) 我有一个使用CodeDOM创建的类:
CodeTypeDeclaration some_class = new CodeTypeDeclaration("SomeClass");
// ... properties and methods creation elided
Run Code Online (Sandbox Code Playgroud)
我想创建一个"SomeClass"类型的List.但是,我似乎无法这样做:
var list_type = new CodeTypeReference(typeof (List<>).Name, ??? some_class ???);
var member_field = new CodeMemberField(list_type, field_name)
{
Attributes = MemberAttributes.Private,
};
Run Code Online (Sandbox Code Playgroud)
CodeTypeReference不接受a CodeTypeDeclaration,这是我需要的.我能做什么?我并不想通过类的字符串名字,因为这可能会导致错误.
我有一种情况,我的代码的一部分是CodeExpressions由用户自己生成的,另一部分是由用户自己生成的(例如:用户只需像往常一样编写代码,然后我会在编译时将其添加到我的程序集中).
是否可以生成包含这两个项目的程序集?警告:这两种方法将包含partial类,因此它们必须位于同一个程序集中.
我想到的另一种方法是将这两种方法转换为字符串表示,然后从该字符串生成程序集,但我怀疑我可以从用户生成的类型中获取源代码(在编译时).
根据这个想法,我可以将CodeExpressions生成的代码写入文本文件并将其与.cs文件结合起来.时间表看起来像这样:
.cs文件的内容.dll从组合源代码中创建一个新的我可以跳过将我生成的CodeDom源写入和读取文本文件的(冗余)步骤,并简单地将其写入内存,当然.事实上,使用预处理T4模板并将这些模板的结果加载到内存中并从该字符串编译程序集可能最简单.
正如你所看到的,这是非常混乱的,但现在它看起来是最可行的.我是否看过任何可能使这更容易的选项?
背景:
我正在创建一个库,该库将创建一个包含用户定义的类的程序集.这种方式的工作方式如下:
TinyTypeSetup实例我现在想要添加的是用户可以创建自己的源文件并立即将这些文件添加到生成的程序集中.这将允许用户使用他自己的方法指定部分类,除了我自己生成的那些.
尝试编译此代码示例:
var c = new CSharpCodeProvider();
var cp = new CompilerParameters();
var className = $"CodeEvaler_{Guid.NewGuid().ToString("N")}";
// doesn't work with or without netstandard reference
var netstandard = Assembly.Load("netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51");
cp.ReferencedAssemblies.Add(netstandard.Location);
cp.CompilerOptions = "/t:library";
cp.GenerateInMemory = true;
var sb = new StringBuilder("");
sb.Append("namespace Jobs.Dynamic{ \n");
sb.Append($"public class {className} {{\n");
sb.Append($"public object RunSnippetCode()\n{{\n");
sb.Append("\nreturn null;\n");
sb.Append("\n}\n");
sb.Append("}");
sb.Append("}");
CompilerResults cr = c.CompileAssemblyFromSource(cp, sb.ToString());
Run Code Online (Sandbox Code Playgroud)
在.netstandard 2.0上进行迁移之前,一切正常
必须生成一个简单的类,并且只要复制代码并在Visual Studio中运行它,它就可以工作。具有一个返回null的方法的类。现在,CompileAssemblyFromSource方法将引发
System.PlatformNotSupportedException:该平台不支持该操作。在Microsoft.CSharp.CSharpCodeGenerator.FromFileBatch(CompilerParameters options,String [] fileNames)在Microsoft.CSharp.CSharpCodeGenerator.System.CodeDom.Compiler.ICodeCompiler.CompileAssemblyFromSourceBatch(CompilerParameters选项,String []源)在CnetContent.Jobs.Dyn。 ctor(IEnumerable
1 referencedAssemblies, IEnumerable1 usings,String methodArgs,String codeSnippet)在CnetContent.Jobs.Core.JobBase.EvalRunCondition(String&错误)
我更新了System.CodeDom,并且此库支持.netstandard …
在服务器上部署时遇到 ASP.NET 错误:
无法找到 CodeDom 提供程序类型“Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”。
此错误仅发生在特定服务器上,在本地或另一台服务器上执行时,它工作得很好。
packages.config CodeDom 行
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.0" targetFramework="net461" />
Run Code Online (Sandbox Code Playgroud)
Web.Config CodeDom 行
<compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/>
Run Code Online (Sandbox Code Playgroud) 有没有人知道用CodeDom调用基类的泛型方法的方法?
调用标准方法没问题,但我找不到调用泛型的解决方案.
我用来调用标准基类方法GetInstance的代码:
CodeAssignStatement assignStatement = new CodeAssignStatement(
new CodeVariableReferenceExpression("instance"),
new CodeMethodInvokeExpression(
new CodeThisReferenceExpression(),
"GetInstance",
new CodeExpression[] { new CodeVariableReferenceExpression("instance") }
));
Run Code Online (Sandbox Code Playgroud) 如何确保从以下代码生成的CS格式良好,即好像我们按下CTRL+ K+ D?这是C#
我们正在做的事情:
CodeMemberMethod membMethod = new CodeMemberMethod();
membMethod.Attributes = MemberAttributes.Static | MemberAttributes.Public;
membMethod.ReturnType = new CodeTypeReference("IEnumerable<" + TableNameAsSinglular + ">");
membMethod.Name = "Get" + TableName;
membMethod.Statements.Add(new CodeSnippetStatement(DataBaseContext + " dcontext = new " + DataBaseContext + "(ConnectionString);"));
membMethod.Statements.Add(new CodeSnippetStatement("var records = from record in dcontext." + TableName + " select new " + TableNameAsSinglular + "{"));
int iCount = 0;
//Add columns fields
foreach (DataRow dr in sqlTable.Rows)
{
if (iCount == 4)
break; …Run Code Online (Sandbox Code Playgroud) 我正在开发一个项目,该项目将使用 CodeDOM 创建一个类,该类评估用户定义的表达式、为该类创建程序集并加载该程序集。由于可以有相当数量的用户定义表达式,我想首先创建一个 AppDomain,为该 AppDomain 中的程序集执行 CodeDOM 创建/加载和执行,然后卸载 AppDomain。
我搜索了不少,并且发现了如何加载现有装配成一个AppDomain的例子很多,但我似乎无法找到一个节目我如何从创建装配中的应用程序域。
此示例 ( DynamicCode ) 使用 CodeDOM 创建一个程序集,然后将其加载到 AppDomain 中,但是,作者将程序集生成到磁盘。我更愿意在内存中生成程序集,这样我就不必管理生成的程序集的清理工作。(即使这确实在临时文件夹中创建了一个 .dll)。
谁能指出我如何做到这一点的例子?
任何帮助将不胜感激。
我已经从我的代码中摘录了一些摘录,这样你们都可以了解我到目前为止的内容:
private string CreateSource()
{
CodeCompileUnit codeUnit = new CodeCompileUnit();
CodeNamespace codeNamespace = new CodeNamespace(Namespace);
CodeTypeDeclaration codeClass = new CodeTypeDeclaration
{
Name = "ExpressionEvaluator",
IsClass = true,
TypeAttributes = TypeAttributes.Public | TypeAttributes.Sealed
};
codeNamespace.Types.Add(codeClass);
codeUnit.Namespaces.Add(codeNamespace);
AddMethods(codeClass);
string result = GenerateSourceCode(codeUnit);
return result.ToString();
}
private CompilerResults CompileSource(string source)
{
using (CodeDomProvider provider = new CSharpCodeProvider())
{
CompilerParameters …Run Code Online (Sandbox Code Playgroud) 有没有人试过在.NET 4.0下使用System.CodeDom生成扩展方法?似乎没有任何方法可以将CodeMemberMethod或CodeParameterDeclarationExpression指定为扩展方法/参数.
如果无法做到这一点,有什么好的解决方法吗?
谢谢
如何从源代码构建CodeCompileUnit?
解析C#源代码的最佳方法是什么?
CodeCompileUnit是正确的选择吗?和怎么样?
谢谢