DynamicObject绑定WRT私有类型 [英] DynamicObject binding WRT private types

查看:162
本文介绍了DynamicObject绑定WRT私有类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下内容:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆