【问题标题】:Attempting to bind a dynamic method on a dynamically-created assembly causes a RuntimeBinderException尝试在动态创建的程序集上绑定动态方法会导致 RuntimeBinderException
【发布时间】:2013-04-10 12:01:05
【问题描述】:

我有一个方便的实用方法,它可以获取代码并生成内存中的程序集。 (它使用CSharpCodeProvider,尽管我认为这不重要。)这个程序集与其他任何反射程序一样工作,但是当与dynamic 关键字一起使用时,它似乎因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;
}

【问题讨论】:

    标签: c# .net dynamic reflection dynamic-language-runtime


    【解决方案1】:

    让你的班级public

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

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

    【讨论】:

    • 我犯了一个愚蠢的错误。 dynamic 尊重可访问性,因此它不能执行来自另一个程序集的非公共代码,而反射并不关心可访问性。谢谢。
    【解决方案2】:

    这可能是一种解决方法。

    //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:我尝试将此作为评论发布(因为它是一种解决方法而不是答案)但不能这样做,因为它太长了......

    【讨论】:

      猜你喜欢
      • 2014-10-15
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 2018-04-22
      • 2014-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多