DynamicObject绑定WRT私有类型 [英] DynamicObject binding WRT private types
问题描述
请考虑以下内容:
using System;
使用System.Dynamic;
命名空间DynamicTest
{
类程序
{
static void Main(string [] args)
{
dynamic d = new DynamicTest();
var v = d.foo();
Console.WriteLine(v.Value);
Console.ReadKey();
}
}
public interface IValueProvider< T>
{
T值
{
get;
}
public class DynamicTest:DynamicObject
{
public override bool TryInvokeMember(InvokeMemberBinder binder,object [] args,out object result)
{
result = new ValueProvider< int>(32);
返回true;
}
私有类ValueProvider< T> :IValueProvider< T>
{
public ValueProvider(T t)
{
this.Value = t;
}
public T Value
{
get;
私人集;
}
}
}
}
在运行时失败:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException未处理
Message ='object'不包含'Value'的定义
Source =匿名托管DynamicMethods Assembly
StackTrace:
在CallSite.Target(Closure,CallSite,Object)
在System.Dynamic.UpdateDelegates.UpdateAndExecute1 [ T0,TRet](CallSite site,T0 arg0)
在DynamicTest.Program.Main(String [] args)
在System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly,String [] args)
在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args)
在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)
在System.Threading.ExecutionContext.Run(ExecutionCont System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state)的
$ System.Threading.ThreadHelper.ThreadStart()
在System.Threading.ThreadHelper.ThreadStart()
$ b InnerException:
如果我更改了 ValueProvider< T>
class to public
而不是 private
它的工作原理如下:
//这允许它工作
public class ValueProvider< T> :IValueProvider< T>
或者,如果我将结果转换为 IValueProvider< int>
它也有效:
//这也允许它工作
dynamic d = new DynamicTest();
var v =(IValueProvider< int>)d.foo();
如果我尝试使用界面作为 TryInvokeMember中的编译时类型/ code>,它不工作(没有真正期望,但以为我会尝试):
//这不帮助
public override bool TryInvokeMember(InvokeMemberBinder binder,object [] args,out object result)
{
var valueProvider =(IValueProvider< int>)new ValueProvider<诠释>(32);
result = valueProvider;
返回true;
}
有人可以指出我在这里失踪吗?有没有办法让我上面的代码工作,而不诉诸使我的所有类型公开和没有投射?
有趣的是,如果可访问性是 internal
:
内部类ValueProvider< T> :IValueProvider< T> (...)
Hassan注释(评论)是有道理的,因为这是可访问性通常需要程序
使用 DynamicTest
(在同一程序集中)的API成员。如果我们将 Main
移动到 DynamicTest
,并将其保留为 private
再次工作,这是我们应该期望的正确的可访问性。
现在可能使用 internal
当然,这里更好的方法就是使用界面。 IMO你不需要 dynamic
here;您可能需要的是非通用的 IValueProvider
:
public interface IValueProvider
{
对象Value {get; }
}
public interface IValueProvider< T> :IValueProvider
{
new T Value {get;
}
与(在课堂上):
对象IValueProvider.Value {get {return Value;
$ b > var v =(IValueProvider)d.foo();
Console.WriteLine(v.Value);
Consider the following:
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;
}
}
}
}
This fails at runtime with:
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:
If I change the ValueProvider<T>
class to public
rather than private
it works as expected:
// this allows it to work
public class ValueProvider<T> : IValueProvider<T>
Or, instead, if I cast the result to IValueProvider<int>
it also works:
// this also allows it to work
dynamic d = new DynamicTest();
var v = (IValueProvider<int>)d.foo();
If I try using the interface as the compile-time type in TryInvokeMember
, it doesn't work (didn't really expect it to, but thought I'd try):
// 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;
}
Can anyone point out what I'm missing here? Is there a way for me to get the code above working without resorting to making all my types public and without casting?
Interestingly, it works if the accessibility is internal
:
internal class ValueProvider<T> : IValueProvider<T> { ... }
which as Hassan notes (comments) makes sense, as that is the accessibility that would normally be required for Program
to use the API members of DynamicTest
(in the same assembly). If we move Main
to DynamicTest
and leave it private
it again works, which is the correct accessibility we should expect.
Maybe use internal
for now.
Of course, an even better approach here would be to just use the interface. IMO you don't need dynamic
here; what you perhaps need is a non-generic IValueProvider
:
public interface IValueProvider
{
object Value { get; }
}
public interface IValueProvider<T> : IValueProvider
{
new T Value{get; }
}
with (in the class):
object IValueProvider.Value { get { return Value; } }
and:
var v = (IValueProvider)d.foo();
Console.WriteLine(v.Value);
这篇关于DynamicObject绑定WRT私有类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!