2016-04-27 59 views
4

实际答案在答案的评论中。我期待得到我的界面的“实例”,这是你无法做到的。为什么Expression.TypeAs的评估返回基础具体类型的对象而不是我请求的接口?

-

I found a way to do what I actually wanted, which for anyone interested, I've outlined below.

public interface Interface<T> { Func<T,T> Property { get; set; } } 

public class Concrete : Interface<string> 
{ 
    public Concrete() 
    { 
     (this as Interface<string>).Property = (s) => { return $"hello, {s}!"; }; 
    } 

    Func<string, string> Interface<string>.Property 
    { 
     get; 
     set; 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     object obj = new Concrete(); 

     var propInfo = obj.GetType().GetInterfaces().Single().GetProperty("Property"); 

     dynamic func = propInfo.GetMethod.Invoke(obj, null); 

     var output = func("world"); 
    }   
} 

-

我做了一些代码生成和我大量使用动态类型的,不幸的是我已经打了动态式/显式接口难题。

我可以通过使用Convert.ChangeType(...)来解决这个问题,如here所示,但是它需要IConvertable被实现,这将会产生大量我不想做的事情。

我有found an example使用Linq表达式来使用Expression.TypeAsExpression.Convert这样做,但是这总是返回底层的具体类型,而不是我需要的接口。

这里是我想要做的代码示例:

namespace ExpressionCasting 
{ 
    public interface Interface<T> { void Method(T t); } 

    public class ImplementedInterface : Interface<string> 
    { 
     void Interface<string>.Method(string t) { } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var implementedInterface = new ImplementedInterface();  

      // type is an IInterface<string> 
      var type = implementedInterface.GetType().GetInterfaces().Single(); 

      // i is always an ImplementedInterface 
      var i = Convert(type, implementedInterface); // i is always an ImplementedInterface 

      Console.WriteLine(i.GetType()); // i want this to be an IInterface<string> nit and ImplementedInterface. 
     } 

     static object Convert(Type type, object subClass) 
     { 
     var body = Expression.TypeAs(
      Expression.Constant(subClass, subClass.GetType()), type); 

     var run = Expression.Lambda(
      body, Expression.Parameter(subClass.GetType())).Compile(); 

     return run.DynamicInvoke(subClass); 
     } 
    } 
} 

任何想法如何,我能得到什么,我需要用表情或如果我没有想到的另一种选择?

+0

你的期望是不是很清楚 - 为什么得到实现接口类的实例是一个问题吗?你还期望什么结果 - 接口没有实例...另外,Mike [在回答中指出](http://stackoverflow.com/a/36894929/477420)'i.Method();'会总是抛出此方法不在界面中 - 确保您的示例实际显示了问题。 –

+0

我认为你的意思是'i.Method(“foo”);'但这实际上并没有改变这里的问题。即使使用'ImpromptuInterface'这是一个很好的Nuget来将动态对象转换为接口,您仍然无法访问像这样的显式实现。 –

+0

顺便说一下你的Convert方法创建一个不使用参数然后用参数调用的lambda体。创建一个参数并将其作为TypeAs的第一个参数而不是常量值传递,或者继续使用常量,并删除传递给DynamicInvoke的lambda参数和参数。 (不会改变问题,只是清理使用)。 –

回答

5

问题不在于你的表达。它与动态的使用。 DLR没有考虑显式的接口实现。这很容易证明,因为下面的代码返回相同的异常:

dynamic i = new ImplementedInterface(); 
i.Method(); // throws exception as method is not found. 

下面是使用动态时,对这个问题的小文章,以及其他的惊喜:http://csharpindepth.com/Articles/Chapter14/DynamicGotchas.aspx

+0

好的答案,如果正确,这意味着问题与标题中提到的内容无关,并可能被封为“印刷错误”...... –

+0

@mike这就是我的意思“不幸的是,我已经达到了动态类型/显式接口难题“。 –

+0

你基本上想要调用一个私有方法。 IE:使用反射到MethodInfo:GetMethod(“Interface .Method”,BindingFlags.Instance | BindingFlags.NonPublic)。你需要实现你自己的DynamicObject来允许这个。 –

1

您正在返回一个对象并将其推入一个动态参数中。它将采用最简单的可能演员阵容,即ImplementedInterface,而不是Interface。您正在有效地撤销在您的Convert方法中完成的投射,方法是将其向下转换为类型对象,然后调用为动态变量。

0

你的表情看起来很不错。 但dynamic本身存在问题。

即使是这种情况下(见下文),你将有一个错误:

public interface Interface<T> { void Method(T t); } 

public class ImplementedInterface : Interface<string> { void Interface<string>.Method(string t) { } } 

void Main() 
{ 
    dynamic i = (Interface<string>)new ImplementedInterface(); 

    i.Method(); // throws exception as method is not found. 
} 
相关问题