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



我有一个方便的实用程序方法,它接受代码并输出内存中的程序集。(它使用CSharpCodeProvider,尽管我认为这应该无关紧要。)这个程序集与反射一样工作,但是当与dynamic关键字一起使用时,它似乎与RuntimeBinderException:

一起失败。

"object"不包含"Sound"的定义

的例子:

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() ...
                               ^

解决了我机器上的问题

这可能是一个变通办法。

//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:我试着把这个作为一个评论(因为它是一个解决方案,而不是一个答案),但不能这样做,因为它是长....

相关内容

  • 没有找到相关文章