请考虑以下几点:
using System;
using System.Dynamic;
namespace DynamicTest
{
class Program
{
static void Main(string[] args)
{
dynamic d = new DynamicTest();
var v = d.foo();
Console.WriteLine(v.Value);
Console.ReadKey();
}
}
public interface IValueProvider<T>
{
T Value
{
get;
}
}
public class DynamicTest : DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
result = new ValueProvider<int>(32);
return true;
}
private class ValueProvider<T> : IValueProvider<T>
{
public ValueProvider(T t)
{
this.Value = t;
}
public T Value
{
get;
private set;
}
}
}
}此操作在运行时失败,出现以下错误:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException was unhandled
Message='object' does not contain a definition for 'Value'
Source=Anonymously Hosted DynamicMethods Assembly
StackTrace:
at CallSite.Target(Closure , CallSite , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
at DynamicTest.Program.Main(String[] args)
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: 如果我将ValueProvider<T>类更改为public而不是private,它将按预期工作:
// this allows it to work
public class ValueProvider<T> : IValueProvider<T>或者,如果我将结果转换为IValueProvider<int>,它也可以工作:
// this also allows it to work
dynamic d = new DynamicTest();
var v = (IValueProvider<int>)d.foo();如果我尝试在TryInvokeMember中使用该接口作为编译时类型,它不会工作(我并没有真正期望它能工作,但我想我会试一下):
// this doesn't help
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var valueProvider = (IValueProvider<int>)new ValueProvider<int>(32);
result = valueProvider;
return true;
}有谁能指出我在这里遗漏了什么吗?有没有一种方法可以让上面的代码正常工作,而不是让我的所有类型都公开,也不需要强制转换?
发布于 2011-08-22 17:04:18
有趣的是,如果可访问性为internal,则可以正常工作
internal class ValueProvider<T> : IValueProvider<T> { ... }正如Hassan所指出的(注释),这是有意义的,因为这是Program使用DynamicTest的API成员(在同一程序集中)通常所需的可访问性。如果我们将Main移到DynamicTest,并将其保留为private,它将再次工作,这是我们应该期望的正确的可访问性。
也许现在可以使用internal。
当然,这里还有一个更好的方法,那就是只使用接口。在这里,您不需要dynamic;您可能需要的是一个非通用IValueProvider
public interface IValueProvider
{
object Value { get; }
}
public interface IValueProvider<T> : IValueProvider
{
new T Value{get; }
}与(在班级中):
object IValueProvider.Value { get { return Value; } }和:
var v = (IValueProvider)d.foo();
Console.WriteLine(v.Value);发布于 2011-08-22 17:01:22
一种解决方案是让ValueProvider<T>也继承DynamicObject,然后在上面实现TryGetMember:
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = this.Value;
return true;
}当然,在本例中,无论您尝试获取什么属性,我们都只是返回值,但我可能会考虑使用字典或ExpandoObject来保留ValueProvider<T>上的可用属性
https://stackoverflow.com/questions/7145029
复制相似问题