8

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

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,用TryInvokeMemberandTryGetMember代替?它们具有相同的访问修饰符。

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

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);
}

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

4

1 回答 1

11
 internal class Entity ....

The dynamic keyword is not a workaround for restricted accessibility. The Entity class is declared internal, so trying to call its Bar() method from code that is not part of the assembly that Entity lives in is going to be rejected by the binder, the message leaves little to the imagination:

EntityLib.Entity.Bar(int)' is inaccessible due to its protection level

The logical way to get ahead is to declare the Entity class public. If that's a problem for some reason then you can break the rules with Reflection. You'll need to use BindingFlags.NonPublic | BindingFlag.Instance options in the Type.GetMethod() call.

As to the core question, I'll happily dismiss that as a bug. The C# DLR binder is impossible to reverse-engineer. Not in the least because the code for it isn't included in the Reference Source, Microsoft does appear to treat it like a trade secret. It is. You can file it at connect.microsoft.com

于 2013-09-14T21:56:22.457 回答