我们有自定义DLL,它们不包含在我们的初始设置文件中.它们在运行时加载.这个过程在使用.NET 2.0时运行良好,但是我们现在正在使用.NET 4.0获得"动态程序集中不支持调用的成员"错误消息.
try
{
assem = Assembly.LoadFrom(fi.FullName); //fi is FileSystemInfo
}
catch (FileLoadException) {}
catch (BadImageFormatException) {}
catch (System.Security.SecurityException) {}
catch (ArgumentException) {}
catch (PathTooLongException) {}
Run Code Online (Sandbox Code Playgroud) 我最近被问到是否对.Net中的动态装配有所了解.简短的回答是 - 我没有.
我发现了很多描述如何创建动态程序集的文章,但没有一篇文章真实地解释了以下内容:
对上述任何解释都将非常感激.
非常感谢.
我正在开发一个允许用户输入任意表达式的库.然后,我的库将这些表达式作为更大表达式的一部分编译到委托中.现在,由于仍然未知的原因,Compile有时/经常编译表达式导致代码远远低于它不是编译表达式时的代码.之前我问了一个关于这个的问题,一个解决方法是不使用Compile,但是在新的动态程序集中CompileToMethod创建static一个新类型的方法.这工作,代码很快.
但是用户可以输入任意表达式,结果是如果用户调用非公共函数或访问表达式中的非公共字段,则System.MethodAccessException在调用委托时抛出(在非公共方法的情况下) .
我可以在这里做的是创建一个新的ExpressionVisitor,检查表达式是否访问非公共的东西,并Compile在这些情况下使用较慢的,但我宁愿让动态程序集以某种方式获得访问非公共成员的权限.或者找出我能做些什么Compile来减慢速度(有时候).
重现此问题的完整代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
namespace DynamicAssembly
{
public class Program
{
private static int GetValue()
{
return 1;
}
public static int GetValuePublic()
{
return 1;
}
public static int Foo;
static void Main(string[] args)
{
Expression<Func<int>> expression = () => 10 + GetValue();
Foo = expression.Compile()(); …Run Code Online (Sandbox Code Playgroud) 我正在研究一个CSharp表达式求值程序,可以使用,如下所示.该组件生成代码并在内存中编译它,之后,它加载生成的程序集,创建生成的类的实例并运行它.结果保存在字典中.
我的问题是所有运行正常,直到最后一行代码失败,异常:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException'object '不包含'FirstName'的定义.
但是,Visual Studio能够向我展示专业变量内容:
Professional = { FirstName = Juan Pablo,
LastName = Ibañez,
Certifications = <>f__AnonymousType0`3[System.String,System.String,System.String][],
SayHi = System.Action }
Run Code Online (Sandbox Code Playgroud)
这是代码:
static void Main(string[] args)
{
const string data = @"results[""professional""] =
new
{
FirstName = ""Juan Pablo"",
LastName = ""Ibañez"",
Certifications = new[]
{
new { Provider=""MSFT"", ExamCode = ""70-536"", Title = ""TS: Microsoft .NET Framework – Application Development Foundation"" },
new { Provider=""MSFT"", ExamCode = ""70-505"", Title = ""TS: Microsoft .NET Framework – Application Development …Run Code Online (Sandbox Code Playgroud) 使用Roslyn编译为动态程序集时,我遇到了性能问题.编译花了大约3秒,相比之下,使用CodeDom编译器编译相同代码的时间约为300毫秒.这是我用来编译的代码的简化版本:
var compilation = CSharpCompilation.Create(
"UserPayRules.dll",
syntaxTrees,
assembliesToAdd);
using (var stream = new MemoryStream())
{
stopWatch.Start();
var result = compilation.Emit(stream);
stopWatch.Stop();
Debug.WriteLine("Compilation: {0}", stopWatch.ElapsedMilliseconds);
if (!result.Success)
{
throw new InvalidOperationException();
}
var assembly = Assembly.Load(stream.GetBuffer());
}
Run Code Online (Sandbox Code Playgroud)
这个答案建议将ModuleBuilder对象传递给Emit方法而不是MemoryStream,以加快速度.我试图遵循这种模式,如下:
var compilation = CSharpCompilation.Create(
"UserPayRules.dll",
syntaxTrees,
assembliesToAdd);
var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("ThisAssembly"),
AssemblyBuilderAccess.RunAndCollect);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("ThisModule");
var result = compilation.Emit(moduleBuilder);
Debug.WriteLine("Compilation: {0}", stopWatch.ElapsedMilliseconds);
if (!result.Success)
{
throw new InvalidOperationException();
}
var assembly = Assembly.Load(stream.GetBuffer());
Run Code Online (Sandbox Code Playgroud)
但我的Roslyn版本显然没有超载的Emit方法需要一个ModuleBuilder …
我希望通过将其保存到光盘或在运行时反映它来获得装配.程序集由第三方在内存中动态生成.
有谁知道如何做到这一点?
我的问题始于将.Net 2.0应用程序移动到.Net 4.0.我必须这样做的原因是Windows 8默认情况下不启用早期的.Net版本,我的应用程序无法要求用户启用它.
该应用程序是一个NPAPI插件,它通过UnmanagedExports使用.Net组件.我将其设计为低完整性应用程序,因此它必须驻留在用户的LocalLow'目录中.
在我的应用程序中,我使用动态程序集加载机制在运行时加载多个程序集.我使用以下方法加载程序集,
MyInterface Instance;
Assembly assembly = Assembly.LoadFrom(AssemblyFile);
Type type = assembly.GetType(Identifier); // Identifier is implementing the MyInterface
Instance = Activator.CreateInstance(type) as MyInterface;
// Do something with the Instance
Run Code Online (Sandbox Code Playgroud)
将项目修改为.Net 4.0之后,我注意到当二进制文件放在LocalLow目录中时插件崩溃(它在其他地方工作).我的下一步是创建一个简约插件,用尽可能少的代码来找出问题.我注意到动态程序集加载失败,出现以下异常,
System.IO.FileLoadException: Could not load file or assembly '<assemblyPath>' or one of its dependencies. Operation is not supported. (Exception from HRESULT: 0x80131515 (COR_E_NOTSUPPORTED)) --->
System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the …Run Code Online (Sandbox Code Playgroud) 我已经编写了.NET和C#多年,但最近才DynamicMethod在反射的上下文中遇到了类型和动态汇编的概念.它们似乎总是在IL(运行时代码)生成中使用.
不幸的是,MSDN在定义动态汇编/方法属性以及它们应该用于什么方面做得非常糟糕.能不能在这里启发我吗?与DLR有什么关系吗?它们如何与运行时静态(正常)生成的程序集和方法不同?我应该知道如何以及何时使用它们?
是否可以创建程序集或模块/类的动态副本?我可以很容易地找到如何从头开始创建使用动态装配或模块AssemblyBuilder/ ModuleBuilder(所看到这里),但有一种方式来创建一个现有的集或类型的副本,其各自的生成器类型?
例如,假设您有一个标准的控制台应用程序,其中包含必需的Program类和Main方法,并且您将另一个类添加到项目中,称为"A".我的目标是A在Main方法中使用ModuleBuilder或类似的东西创建类的动态副本.
我想要复制类的原因A是因为我想要一个完全相同的类A,包括方法,字段,属性等,但是动态创建.我不想要的是,必须使用TypeBuilder/CodeDom手动创建类型及其所有成员(方法,字段,属性等),因为在某些情况下,我可能不知道所有关于一个类及其内部工作或类可能很大,繁琐/不可能使用这种方法重现.
希望一些伪代码可以说明我在寻找什么:
// create AssemblyBuilder using the assembly of the A class so you end up with a
// dynamic copy of the assembly
AssemblyBuilder ab = new AssemblyBuilder(Assembly.GetAssembly(typeof(A)));
// get the Type as a TypeBuilder from the AssemblyBuilder
TypeBuilder tb = ab.GetModule("Test.exe").GetType(typeof(A).FullName);
Run Code Online (Sandbox Code Playgroud)
我基本上只想把它Assembly当作一个AssemblyBuilder或Type一个TypeBuilder.我也不需要能够保存程序集.
我正在开发一个项目,我们正在使用DLR将Racket语言移植到.NET.
我们构建一个表达式树并调用CompileToMethod()Method:
相关的可执行发射代码:(取自如何将表达式树保存为新的可执行磁盘文件的主要入口点?)
//Wrap the program into a block expression
Expression code = Expression.Block(new ParameterExpression[] { env, voidSingleton}, program);
var asmName = new AssemblyName("Foo");
var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = asmBuilder.DefineDynamicModule("Foo", "Foo.exe");
var typeBuilder = moduleBuilder.DefineType("Program", TypeAttributes.Public);
var methodBuilder = typeBuilder.DefineMethod("Main",
MethodAttributes.Static, typeof(void), new[] { typeof(string) });
Expression.Lambda<Action>(code).CompileToMethod(methodBuilder);
typeBuilder.CreateType();
asmBuilder.SetEntryPoint(methodBuilder);
asmBuilder.Save("Foo.exe");
Run Code Online (Sandbox Code Playgroud)
我们有我们的运行时库Runtime_rkt.dll,它包含相关的运行时类型转换,后备对象等.
当我们将Foo.exe和Runtime_rkt.dll在同一目录下,一切工作正常.我们遇到的问题是当我们(显然)将运行时库移动到其他地方时.最终我们想要C:\Windows\Microsoft.NET\assembly\GAC_MSIL像IronPython一样安装它.[使用GAC解决]
[编辑]额外的新问题有没有办法我们可以将所有运行时方法静态编译成可执行文件?
我正在尝试将表达式树导出到PE程序集作为主要入口点.我通过构建表达式树获得了Lambda Expression,例如:
using System.Linq;
using System;
// 1. use expression trees to create a block expression (not shown)
// 2. create a lambda expression:
LambdaExpression exprLambda = Expression.Lambda(exprBlock, new ParameterExpression[0]);
MethodBuilder mbuilder = null;
// 3. ??? Somehow get a method builder instance that works ???
// 4. Compile the lambda using the MethodBuilder instance.
exprLambda.CompileToMethod(mbuilder);
// 5. ??? Somehow get an AssemblyBuilder instance to .Save(..) this to disk. ???
Run Code Online (Sandbox Code Playgroud)
第3步和第5步是我所缺少的.