我有一个包含以下类的库:
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
并使用TryInvokeMember
和TryGetMember
代替?它们具有相同的访问修饰符。
更新:在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);
}
这是一个错误还是一个功能是由微软决定的。但是,我希望将变量转换为动态不应限制访问。
答案 0 :(得分:8)
internal class Entity ....
动态关键字不是限制可访问性的变通方法。 Entity类被声明为 internal ,因此尝试从不属于实体所在的程序集的代码调用其Bar()方法将被绑定器拒绝,该消息几乎没有想象力:
由于其保护级别,EntityLib.Entity.Bar(int)'无法访问
获得成功的合理方法是声明实体类 public 。如果由于某种原因这是一个问题,那么你可以用反射破坏规则。你需要使用BindingFlags.NonPublic | Type.GetMethod()调用中的BindingFlag.Instance选项。
关于核心问题,我很高兴地认为这是一个错误。 C#DLR绑定器无法进行逆向工程。至少因为它的代码没有包含在参考源中,微软确实将其视为商业秘密。它是。您可以在connect.microsoft.com上提交文件