[英]C# - Create an instance of a class with generic type parameters without specifying these types
[英]How do I use a generic class without specifying its type parameters in C#?
我知道之前已经问过多个类似的问题,但是我仍然相信这个特定的问题还没有解决。
有一个 class Super
和一个通用 class Foo<T>: Super
,它们都来自第三方库。 我需要扩展Foo<T>
的功能,所以我有这个通用的 class:
public class Bar<T, U> : Foo<T> {
public void DoSomething() { ... }
// Other things that use T and U
}
我现在想要一个“酒吧”的集合(列表),并且能够在所有这些上调用 DoSomething。 所以从逻辑上讲,当调用 void 方法时,我不关心 Bar 的类型参数,因为它在那种情况下是无关紧要的。
此外,第三方库还公开了以下方法:
public LibraryMethod(Super super) { ... }
而且我需要能够用我的任何“酒吧”调用该方法。
我不能使用接口的原因是,因为第三方库在它公开的一些方法中期望Super
,并且接口可以由任何 class 实现,所以我不能将我的 Bar 用作 Super,即使每个 Bar (不管它的类型 arguments 是什么)必须是超级。 该接口基本上破坏了 inheritance 链,我不能再将我的“Bar”传递给期望 Super 的方法。
显然,由于与上述相同的原因,我不能让Bar<T, U>
从非泛型基础 class 继承。 它也会破坏 inheritance 链。
在理想情况下,我可以这样做:
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]);
您可以将方法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());
简而言之,在 C# 之类的强类型语言中,您不能轻易做到这一点。
可以这样想(简化): List<T>
需要知道 memory 中的T
有多大,因此它可以为其默认数量的条目保留足够的空间。 编译器不能保证Type1
和Type3
的大小相同,也不能保证Type2
和Type3
。
您可能会在编译时丢失类型信息并在其他地方进行跟踪。 也许你有程序知识(你,程序员)并且知道类型信息。 否则,您必须创建一些数据结构并携带此信息。 无论如何,您可以在这里使用接口。
考虑您目前的情况(不起作用):
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);
}
}
output:
> Main()
i do something
i'm super
i do something
i'm super
你不能做你描述的事情。 用 List 或 KeyValuePair 替换您的酒吧 class 以查看结果:
var myList = new List<List<>>();
var myListOfKv = new List<KeyValuePair<>>();
您正在尝试分配一些 memory,编译器需要知道一些约束。 您可以尝试对以下类型进行一些限制: class Bar<x,y>:Foo where x is ISoda
您可能还会想到另一种方法来扩展功能,方法是在您的孩子中添加特定的方法来处理对象:
class Bar<x>: Foo<x>
{
public void Inject(Iy iy);
public void UseInjected();
}
第三方库仍将接受 Bar 实例并忽略新功能。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.