簡體   English   中英

顯式接口和通用/動態類型轉換

[英]Explicit Interface And Generic / Dynamic Type Conversion

在陳述問題之前,請允許我提供一些我想做的事情的背景信息,因為也許有更好的方法可以實現它。

我有一個C類,它繼承了AB兩個接口。

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轉換為AB ,然后在AB上調用DoStuff

所以我雖然可以實現一個通用方法來為我做這件事,所以我首先嘗試這樣。

public void DoStuff<T>()
{
    var i = (T)this;
    i.DoStuff();
}

當然,這是行不通的考慮,你可以轉換的thisT ,它會導致一個編譯器錯誤,所以我的下一步是嘗試創建通過實例的靜態方法, 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方法來實現此目的,我將如何進行從dynamicT的轉換? 有沒有一種方法可以檢查傳遞給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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM