我知道之前已經問過多個類似的問題,但是我仍然相信這個特定的問題還沒有解決。
有一個類Super和一個泛型類Foo<T> : Super,它們都來自第三方庫。我需要擴展的功能Foo<T>所以我有這個通用類:
public class Bar<T, U> : Foo<T> {
public void DoSomething() { ... }
// Other things that use T and U
}
我現在想要一個“酒吧”的集合(串列),并且能夠在所有這些上呼叫 DoSomething。所以從邏輯上講,當呼叫 void 方法時,我不關心 Bar 的型別引數,因為它在那種情況下是無關緊要的。
此外,第三方庫還公開了以下方法:
public LibraryMethod(Super super) { ... }
而且我需要能夠用我的任何“酒吧”呼叫該方法。
非解決方案 1:介面
我不能使用介面的原因是,因為第三方庫Super在它公開的一些方法中需要一個介面,并且介面可以由任何類實作,所以我不能將我的 Bar 用作 Super 的,即使每個 Bar(沒有不管它的型別引數是什么)必須是一個超級。該介面基本上破壞了這里的繼承鏈,我不能再將我的“Bar”傳遞給期望 Super 的方法。
非解決方案 2:非泛型基類
顯然,由于與上述相同的原因,我不能Bar<T, U>從非泛型基類繼承。它也會破壞繼承鏈。
虛構的理想情況
在理想情況下,我可以這樣做:
List<Bar<>> bars = new List<Bar<>>();
bars.Add(new Bar<Type1, Type2>());
bars.Add(new Bar<Type3, Type4>());
foreach (Bar<> bar in bars) {
bar.DoSomething();
}
LibraryMethod(bars[0]);
uj5u.com熱心網友回復:
您可以將方法添加AsSuper到您的界面:
public interface IBar
{
void DoSomething();
Super AsSuper();
}
這應該很容易實作Bar:
public class Bar<T, U> : Foo<T>, IBar {
public void DoSomething() { ... }
public Super AsSuper() => this;
// Other things that use T and U
}
這將允許您安全地鍵入呼叫LibraryMethod:
LibraryMethod(bars[0].AsSuper());
uj5u.com熱心網友回復:
您可能會在編譯時丟失型別資訊并在其他地方進行跟蹤。也許你有程式知識(你,程式員)并且知道型別資訊。否則,您必須創建一些資料結構并攜帶此資訊。無論如何,您可以在這里使用介面。
考慮您目前的情況(不起作用):
public class Super { public int SuperData { get; set; } }
public class Foo<T> : Super { public T FooData { get; set; } }
public class Bar<T, U> : Foo<T>
{
public U BarData { get; set; }
public void DoSomething()
{
Console.WriteLine("i do something");
}
}
public static void LibraryMethod(Super super) { Console.WriteLine("i'm super"); }
public void Main()
{
// generic "object" collection
var listy = new List<object>();
listy.Add(new Bar<int, double>());
listy.Add(new Bar<DateTime, bool>());
foreach (var x in listy)
{
x.DoSomething(); /// 'object' does not contain a definition for 'DoSomething'
// and then call your library
LibraryMethod((Super)x);
}
}
相反,添加一個介面并在您的型別中實作:
public interface IDoSomething
{
void DoSomething();
}
public class Bar<T, U> : Foo<T>, IDoSomething
{
public U BarData { get; set; }
public void DoSomething()
{
Console.WriteLine("i do something");
}
}
現在您可以使用 with cast 來更正介面型別:
public void Main()
{
var listy = new List<object>();
listy.Add(new Bar<int, double>());
listy.Add(new Bar<DateTime, bool>());
foreach (var x in listy)
{
var bar = x as IDoSomething;
// check null reference
bar.DoSomething();
// and then call your library
LibraryMethod((Super)x);
}
}
輸出:
> Main()
i do something
i'm super
i do something
i'm super
uj5u.com熱心網友回復:
你不能做你描述的事情。用 List 或 KeyValuePair 替換您的 bar 類以查看結果:
var myList = new List<List<>>();
var myListOfKv = new List<KeyValuePair<>>();
您正在嘗試分配一些記憶體,編譯器需要知道一些約束。您可以嘗試對以下型別進行一些限制: class Bar<x,y> :Foo where x is ISoda
您可能還會想到另一種方法來擴展功能,方法是在您的孩子中添加特定的方法來處理物件:
class Bar<x>: Foo<x>
{
public void Inject(Iy iy);
public void UseInjected();
}
第三方庫仍將接受 Bar 實體并忽略新功能。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/510445.html
標籤:C#仿制药通用类型参数
上一篇:只寫集合的意義何在?
