尝试在动态创建的程序集上绑定动态方法会导致RuntimeBinderException

问题描述:

我有一个方便的实用程序方法,它需要代码并将内存程序集分出。 (它使用CSharpCodeProvider,虽然我不认为应该没关系。)该组件像任何其他与反思,但与dynamic关键字使用时,它似乎无法用RuntimeBinderException尝试在动态创建的程序集上绑定动态方法会导致RuntimeBinderException

“对象”不包含“声音”的定义

例子:

var assembly = createAssembly("class Dog { public string Sound() { return \"woof\"; } }"); 
var type = assembly.GetType("Dog"); 
Object dog = Activator.CreateInstance(type); 

var method = type.GetMethod("Sound"); 
var test1Result = method.Invoke(dog, null); //This returns "woof", as you'd expect 

dynamic dog2 = dog; 
String test2Result = dog2.Sound(); //This throws a RuntimeBinderException 

有谁知道为什么DLR是无法处理这种情况的原因?有什么可以解决这个问题吗?

编辑:

createAssembly方法:

免责声明:一些这方面的东西包含扩展方法,自定义类型等,这应该是不言自明,但。

private Assembly createAssembly(String source, IEnumerable<String> assembliesToReference = null) 
{ 
    //Create compiler 
    var codeProvider = new CSharpCodeProvider(); 

    //Set compiler parameters 
    var compilerParameters = new CompilerParameters 
    { 
     GenerateInMemory = true, 
     GenerateExecutable = false, 
     CompilerOptions = "/optimize", 
    }; 

    //Get the name of the current assembly and everything it references 
    if (assembliesToReference == null) 
    { 
     var executingAssembly = Assembly.GetExecutingAssembly(); 
     assembliesToReference = executingAssembly 
      .AsEnumerable() 
      .Concat(
       executingAssembly 
        .GetReferencedAssemblies() 
        .Select(a => Assembly.Load(a)) 
      ) 
      .Select(a => a.Location); 
    }//End if 

    compilerParameters.ReferencedAssemblies.AddRange(assembliesToReference.ToArray()); 

    //Compile code 
    var compilerResults = codeProvider.CompileAssemblyFromSource(compilerParameters, source); 

    //Throw errors 
    if (compilerResults.Errors.Count != 0) 
    {     
     throw new CompilationException(compilerResults.Errors);     
    } 

    return compilerResults.CompiledAssembly; 
} 

让你public类。

var assembly = createAssembly("public class Dog { public string Sound() ... 
          ^

这解决了我的机器上的问题。

+0

我的部分愚蠢的错误。 'dynamic'尊重可访问性,所以它不能从另一个程序集执行非公共代码,而反射并不关心可访问性。谢谢。 – MgSam

这可能是一个工作周期。

//instead of this 
//dynamic dog2 = dog;  

//try this 
dynamic dog2 = DynWrapper(dog);  
String test2Result = dog2.Sound();//Now this works. 

public class DynWrapper : DynamicObject { 
     private readonly object _target; 


     public DynWrapper(object target) { 
      _target = target;     
     } 

     public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { 
      //for the sake of simplicity I'm not taking arguments into account, 
      //of course you should in a real app. 
      var mi = _target.GetType().GetMethod(binder.Name); 
      if (mi != null) { 
       result = mi.Invoke(_target, null);           
       return true; 
      } 
      return base.TryInvokeMember(binder, args, out result); 
     } 
    } 

PS:我尝试发布此为注释(因为它是一个workarround不是一个答案),但不能这样做怎么一回事,因为它的长....