为什么C#dynamic解析内部属性而不解析方法?

时间:2013-09-12 13:54:53

标签: c# dynamic

我有一个包含以下类的库:

public interface IEntity
{
    string Foo { get; }
    void Bar(int x);
}

public class EntityFactory 
{
    public static IEntity createEntity() 
    {
        return new Entity();
    }
}

internal class Entity : DynamicObject, IEntity
{
    public void Bar(int x)
    {
        Console.WriteLine("inside Bar");
        Console.WriteLine("bar {0}", x);
    }

    public string Foo
    {
        get 
        {
            Console.WriteLine("inside Foo getter");
            return "foo";
        }
    }

    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        Console.WriteLine("inside TryInvokeMember(binder.Name = '{0}')", binder.Name);
        return base.TryInvokeMember(binder, args, out result);
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        Console.WriteLine("inside TryGetMember(binder.Name = '{0}')", binder.Name);
        if (binder.Name == "SomeVar")
        {
            result = 42;
            return true;
        }
        return base.TryGetMember(binder, out result);
    }
}

以及使用它们的程序:

public static void Main(string[] args)
{
    dynamic entity = EntityFactory.createEntity();
    Console.WriteLine("entity.Foo = {0}", entity.Foo);
    entity.Bar(24);
    Console.WriteLine("entity.SomeVar = {0}", entity.SomeVar);
}

输出

inside Foo getter
entity.Foo = foo
inside TryInvokeMember(binder.Name = 'Bar')
inside TryGetMember(binder.Name = 'Bar')

然后我收到一个例外

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: `EntityLib.Entity.Bar(int)' is inaccessible due to its protection level

为什么动态对象直接访问属性Foo,但无法调用方法Bar并使用TryInvokeMemberTryGetMember代替?它们具有相同的访问修饰符。

更新:在Mono上观察到所描述的行为。访问Foo属性时,Microsoft已失败。以下代码按预期工作:

public static void Main(string[] args)
{
    var entity = EntityFactory.createEntity();
    entity.Bar(24);
    Console.WriteLine("entity.Foo = {0}", entity.Foo);

    dynamic e = entity;
    Console.WriteLine("entity.SomeVar = {0}", e.SomeVar);
}

这是一个错误还是一个功能是由微软决定的。但是,我希望将变量转换为动态不应限制访问。

1 个答案:

答案 0 :(得分:8)

 internal class Entity ....

动态关键字不是限制可访问性的变通方法。 Entity类被声明为 internal ,因此尝试从不属于实体所在的程序集的代码调用其Bar()方法将被绑定器拒绝,该消息几乎没有想象力:

  由于其保护级别,

EntityLib.Entity.Bar(int)'无法访问

获得成功的合理方法是声明实体类 public 。如果由于某种原因这是一个问题,那么你可以用反射破坏规则。你需要使用BindingFlags.NonPublic | Type.GetMethod()调用中的BindingFlag.Instance选项。

关于核心问题,我很高兴地认为这是一个错误。 C#DLR绑定器无法进行逆向工程。至少因为它的代码没有包含在参考源中,微软确实将其视为商业秘密。它是。您可以在connect.microsoft.com上提交文件