简体   繁体   English

如何使用通用 class 而不在 C# 中指定其类型参数?

[英]How do I use a generic class without specifying its type parameters in C#?

I'm aware that multiple similar sounding questions have been asked before, however I still believe that this particular problem has not been solved yet.我知道之前已经问过多个类似的问题,但是我仍然相信这个特定的问题还没有解决。

There is a class Super and a generic class Foo<T>: Super , which both come from a third-party library.有一个 class Super和一个通用 class Foo<T>: Super ,它们都来自第三方库。 I need to extend the functionality of Foo<T> so I have this generic class:我需要扩展Foo<T>的功能,所以我有这个通用的 class:

public class Bar<T, U> : Foo<T> {
  public void DoSomething() { ... }

  // Other things that use T and U
}

I now want to have a collection(list) of "Bar's" and be able to call DoSomething on all of them.我现在想要一个“酒吧”的集合(列表),并且能够在所有这些上调用 DoSomething。 So logically, I dont care about the type argument of Bar, when calling the void method as it is irrelevant in that scenario.所以从逻辑上讲,当调用 void 方法时,我不关心 Bar 的类型参数,因为它在那种情况下是无关紧要的。

Additionally the third-party library exposes methods such as:此外,第三方库还公开了以下方法:

public LibraryMethod(Super super) { ... }

And I need to be able to call that method with any of my "Bar's".而且我需要能够用我的任何“酒吧”调用该方法。

Not-A-Solution 1: Interfaces非解决方案 1:接口

The reason why I cant use an interface is, because the third-party library expects a Super in some of the methods it exposes, and an interface can be implemented by any class, so I cannot use my Bar's as Super's even though every Bar (no matter what its type arguments are) must be a Super.我不能使用接口的原因是,因为第三方库在它公开的一些方法中期望Super ,并且接口可以由任何 class 实现,所以我不能将我的 Bar 用作 Super,即使每个 Bar (不管它的类型 arguments 是什么)必须是超级。 The interface essentially ruins the inheritance chain here and I can no longer pass my "Bar's" to methods expecting a Super.该接口基本上破坏了 inheritance 链,我不能再将我的“Bar”传递给期望 Super 的方法。

Not-A-Solution 2: Non-Generic Base Class非解决方案 2:非通用基础 Class

Obviously I cannot make Bar<T, U> inherit from a non-generic base class, as per the same reason as above.显然,由于与上述相同的原因,我不能让Bar<T, U>从非泛型基础 class 继承。 It would ruin the inheritance chain as well.它也会破坏 inheritance 链。

Fictional Ideal Situation虚构的理想情况

In an ideal situation I could do something like this:在理想情况下,我可以这样做:

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]);

You can add method AsSuper to your interface:您可以将方法AsSuper添加到您的界面:

public interface IBar
{
   void DoSomething();
   Super AsSuper();
}

Which should be easily implemented in Bar :这应该很容易在Bar中实现:

public class Bar<T, U> : Foo<T>, IBar {
  public void DoSomething() { ... }
  public Super AsSuper() => this;
  // Other things that use T and U
}

Which will allow you to type safely invoke LibraryMethod :这将允许您安全地键入调用LibraryMethod

LibraryMethod(bars[0].AsSuper());

Simply put, you cannot do that easily in a strongly typed language such as C#.简而言之,在 C# 之类的强类型语言中,您不能轻易做到这一点。

Think of it this (simplified) way: a List<T> needs to know how big T in memory, so it can reserve enough space for its default number of entries.可以这样想(简化): List<T>需要知道 memory 中的T有多大,因此它可以为其默认数量的条目保留足够的空间。 There is no guarantee to the compiler that Type1 and Type3 are the same size, nor Type2 and Type3 .编译器不能保证Type1Type3的大小相同,也不能保证Type2Type3

You can lose type information at compile time and track this elsewhere.您可能会在编译时丢失类型信息并在其他地方进行跟踪。 Maybe you have program knowledge (you, the programmer) and know type information.也许你有程序知识(你,程序员)并且知道类型信息。 Otherwise you have to create some data structure and carry this information around.否则,您必须创建一些数据结构并携带此信息。 Anyways, you can use interfaces here.无论如何,您可以在这里使用接口。

Consider your current situation (does not work):考虑您目前的情况(不起作用):

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);
    }
}

Instead, add an interface and implement in your type:相反,添加一个接口并在您的类型中实现:

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");
    }
}

Now you can use with cast to correct interface type:现在您可以使用 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: output:

> Main()
i do something
i'm super
i do something
i'm super

You cannot do what you describe.你不能做你描述的事情。 replace your bar class by List or KeyValuePair to see what it result in:用 List 或 KeyValuePair 替换您的酒吧 class 以查看结果:

var myList = new List<List<>>(); 
var myListOfKv = new List<KeyValuePair<>>(); 

you are trying to allocate some memory, the compiler needs to know some constraints.您正在尝试分配一些 memory,编译器需要知道一些约束。 you can maybe try to put some restrictions on types like: class Bar<x,y>:Foo where x is ISoda您可以尝试对以下类型进行一些限制: class Bar<x,y>:Foo where x is ISoda

you might also think of another way to extend functionnality by adding in your children specific method to handle objects:您可能还会想到另一种方法来扩展功能,方法是在您的孩子中添加特定的方法来处理对象:

class Bar<x>: Foo<x>
{
    public void Inject(Iy iy);
    public void UseInjected();
}

The third party lib will still accept the Bar instances and ignore new functionnality.第三方库仍将接受 Bar 实例并忽略新功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C# - 使用泛型类型参数创建 class 的实例而不指定这些类型 - C# - Create an instance of a class with generic type parameters without specifying these types C#使用泛型类而不指定类型 - C# Using Generic Class without Specifying Type 如何在C#中将常规类型参数作为常规类型访问和使用? - How do I access and use generic type parameters as a regular type in C#? 没有指定类型的C#通用方法 - C# Generic Method Without Specifying Type 在 C# 中指定泛型类型参数时如何使用`dynamic`? - How to use the `dynamic` when specifying generic type arguments in C#? 泛型类型参数 C# - 如何泛型 class 返回类型 - Generic type parameters C# - How to generic class return type C#/ReportViewer:如何在不指定参数名称的情况下使用参数 - C#/ReportViewer: How to use parameters without specifying parameter names C#-如何在“通用类”类型的MainForm类中声明变量而不指定通用类型 - C# - How can I declare a variable in MainForm class of type “Generic Class” without specifing generic type 是否可以在不指定类型的情况下引用通用 class object? - Is it possible to reference a generic class object without specifying its type? 如何在不指定任何类型参数的情况下创建构造的泛型类型 - How to create a constructed generic type without specifying any type parameters
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM