2016-04-27 14 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. 
} 
相關問題