2016-11-24 88 views
0
public interface IFoo { } 
public abstract class IFooDerived : IFoo { } 
public class Foo : IFooDerived { } 

public interface IBar { } 
public abstract class IBarDerived : IBar { } 
public class Bar : IBarDerived { } 

public interface IExample<out A, B> where A : IFoo where B : IBar 
{ 
    A Foo(B b); 
} 

public class Example : IExample<Foo, Bar> 
{ 
    static Example example = new Example(); 
    static Example() 
    { 
     Example ex = example; 

     IExample<IFoo, IBar> ex_huh = ex; //How can I do this? 

     //Or is there a way where I can say I don't care, but I still want to reference ex, like this: 
     IExample<object,object> ex_huh2 = ex; 
     //Or: 
     IExample<, > ex_huh2 = ex; 

     ex_huh2.Foo(new Bar()); //And still call Foo? 
    } 

    public Foo Foo(Bar b) 
    { 
     throw new NotImplementedException(); 
    } 
} 

在上面的例子中,我如何在不知道其泛型類型的情況下對靜態示例變量進行降級和引用,但仍能夠調用「A Foo(B b)」?c#協議屬性/通用訪問的泛型?

是否有這樣做的強類型的方式?

回答

1
IExample<IFoo, IBar> ex_huh = ex; //How can I do this? 

你不能,因爲它會破壞類型安全。這是因爲你試圖使你的方法的參數類型(該參數爲Foo(B b))更一般化,這是不安全的。

爲了更容易理解爲什麼這是一個問題,讓我們熬你的榜樣下來的東西當量(只要該方法參數雲):

function DoSomethingWithFoo(Foo foo) { ... } 
// The following line won't compile, but let's pretend it does and see what happens 
Action<IFoo> doSomethingWithIFoo = DoSomethingWithFoo; 
doSomethingWithIFoo(new OtherFoo()); 

其中OtherFoo是實現IFoo一些其他類,但不會從Foo類下降。

哎呦!你打電話DoSomethingWithFoo,它預計Foo的實例,但通過OtherFoo而不是!古怪的hijinks隨之而來。

這是本質你想在你的例子做什麼。您正在嘗試使用期望類型爲Foo的參數的方法,並將其轉換爲可讓您通過任何IFoo的方法。

(這就是爲什麼編譯器不會讓你聲明的IExampleB類型參數爲out B,這是它必須是讓你施放一個IExample<..., Foo>IExample<..., IFoo>。編譯器看到的是,B類型參數作爲一個方法參數的類型,並因此使其協變會破壞類型安全)


至於如何完成你在找什麼:那將依賴。你想要的具體例子做

IExample<...figure out how to declare this...> = ...any IExample<A, B>...; 
ex_huh2.Foo(new Bar()); 

是不會在一般的工作,因爲「......任何IExample<A, B> ......」很可能是一個IExample<..., OtherBar>,然後你不能傳遞一個new Bar()。你必須弄清楚你想如何解決這個衝突。

也許你確實想在new Bar()通過,在這種情況下,也許你想這樣做,多數民衆贊成限制爲只與Bar服用IExample S作爲他們的第二個類型參數的方法中:

public void AddABar<TFoo>(IExample<TFoo, Bar> example) 
{ 
    example.Foo(new Bar()); 
} 

或者也許你想創建一個新的實例不管的第二個類型參數是:

public void AddAThing<TFoo, TBar>(IExample<TFoo, TBar> example) 
    where TBar : new() 
{ 
    example.Foo(new TBar()); 
} 

或者,也許你想IExample<A, B>從非通用下降0聲明一個非通用的Foo(IBar b),在你的Example類上實現該非泛型方法,並在該方法內執行一個類型轉換爲B - 如果在運行時將錯誤類型傳入該方法,得到一個InvalidCastException

這實際上都歸結爲你想如何解決這個衝突的「我想把這個東西我可以通過new Bar()」的衝突,當事實上任何給定的實施IExample<A, B>不一定能夠接受new Bar()作爲方法參數。