[英]Explicit Interface And Generic / Dynamic Type Conversion
在陳述問題之前,請允許我提供一些我想做的事情的背景信息,因為也許有更好的方法可以實現它。
我有一個C
類,它繼承了A
和B
兩個接口。
public interface A
{
void DoStuff();
}
public interface B
{
void DoStuff();
}
C為DoStuff
實現了兩個不同的主體。
void A.DoStuff()
{
Console.WriteLine("A");
}
void B.DoStuff()
{
Console.WriteLine("B");
}
我當然知道DoStuff
可以這樣稱呼。
var c = new C();
var a = (A)c;
a.DoStuff();
var b = (B)c;
b.DoStuff();
我要做的是避免將C
轉換為A
或B
,然后在A
或B
上調用DoStuff
。
所以我雖然可以實現一個通用方法來為我做這件事,所以我首先嘗試這樣。
public void DoStuff<T>()
{
var i = (T)this;
i.DoStuff();
}
當然,這是行不通的考慮,你可以轉換的this
以T
,它會導致一個編譯器錯誤,所以我的下一步是嘗試創建通過實例的靜態方法, this
在那里,然后做了轉換。
private static To ConvertToDoStuffInterface<From, To>(From from)
{
return (To)from;
}
我沒想到它能起作用,但是值得一試。 如我所料,它將導致編譯器錯誤,因為From
無法顯式轉換為To
。
我的最后一招是使用dynamic
關鍵字,當然它可以通過ConvertToDoStuffInterface
平滑地獲取,但是一旦我嘗試調用DoStuff
它就會拋出RuntimeBinderException
,我懷疑這可能會。 我知道為什么會引發異常,這當然是因為它不能正確地將ConvertToDoStuffInterface
的結果綁定到任何類型,並且我認為需要某種類型的轉換。
這是dynamic
用法的代碼。
private static dynamic ConvertToDoStuffInterface<T>(dynamic from)
{
return (T)from;
}
public void DoStuff<T>()
{
var i = ConvertToDoStuffInterface<T>(this);
i.DoStuff();
}
我的問題是,如果沒有更好的方法來使用泛型或dynamic
方法來實現此目的,我將如何進行從dynamic
到T
的轉換? 有沒有一種方法可以檢查傳遞給DoStuff<T>
類型是否具有DoStuff
方法,然后允許我首先嘗試使用的方法?
澄清我想做的事情是這樣的
var c = new C();
c.DoStuff<A>(); // Calls A.DoStuff()
c.DoStuff<B>(); // Calls B.DoStuff()
這是我的C
實現。
public class C : A, B
{
public void DoStuff<T>()
{
// ... DoStuff<T> implementation here ...
}
void A.DoStuff()
{
Console.WriteLine("A");
}
void B.DoStuff()
{
Console.WriteLine("B");
}
}
您可以使用這兩種InvokeAs
擴展方法
public static void InvokeAs<T>(this object obj, Action<T> action)
{
action((T) obj);
}
public static TResult InvokeAs<T, TResult>(this object obj, Func<T, TResult> func)
{
return func((T) obj);
}
然后像這樣使用:
var c = new C();
c.InvokeAs<A>(x => x.DoStuff());
c.InvokeAs<B>(x => x.DoStuff());
但是正如評論中指出的那樣, ((B) c).DoStuff()
並不是那么糟糕。
要完全具有所需的行為,可以使用反射:
class C : A, B
{
void B.DoStuff()
{
Console.WriteLine("B");
}
void A.DoStuff()
{
Console.WriteLine("A");
}
public void DoStuff<T>()
{
var mi = typeof(T).GetMethod("DoStuff");
mi.Invoke(this, new object[] { });
}
}
然后調用:
var c = new C();
c.DoStuff<A>();
c.DoStuff<B>();
Console.ReadLine();
如預期般運作。 顯然,如果存在“ DoStuff”方法,則必須在DoStuff方法中進行正確的驗證,依此類推。
但是-我不知道用例-但對我來說,為什么這比鑄造更適合您似乎並不那么明顯。
我同意強制轉換可能是最干凈的(假設您無法解決接口中的名稱沖突),但是另一種方法是在C
上創建兩個實例方法來包裝接口調用:
public class C : A, B
{
public void DoStuff<T>()
{
// ... DoStuff<T> implementation here ...
}
void A.DoStuff()
{
Console.WriteLine("A");
}
void B.DoStuff()
{
Console.WriteLine("B");
}
public void DoStuffAsA() { ((A)this).DoStuff(); }
public void DoStuffAsB() { ((B)this).DoStuff(); }
}
至少它為您提供了dynamic
,反射和泛型所沒有的編譯時安全性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.