【问题标题】:What is the purpose of a restricting the type of generic in a method?限制方法中泛型类型的目的是什么?
【发布时间】:2016-03-10 18:12:22
【问题描述】:

我很难理解为什么这样做会有好处:(示例是一个类)

static void PrintResults<T>(T result) where T : Sample

将 Sample 传递给方法不是更好吗?

 static void PrintResults (Sample result)

【问题讨论】:

  • 对于传递给方法的东西,好处确实很小。对于再次返回的东西,它会有所帮助,因为消费者不需要投射。

标签: c# oop


【解决方案1】:

我建议避免使用非泛型语法的泛型类型,例如您给出的示例。但是,还有其他有用的案例。

例如,一般指定返回类型:

static T Create<T>() where T: Sample, new()
{
    return new T();
}

// Calling code
Sample sample = Create<Sample>();

而不是

static object Create()
{
    return new Sample();
}

// Calling code
Sample sample = (Sample) Create();

您还可以使用模板对一个类型设置多个限制。例如:

static T Create<T>() where T: IMyInterface, new()
{
    return new T();
}

interface IMyInterface {} 
class MyClass : IMyInterface { }

// Calling code.
MyClass myClass = Create<MyClass>();

这允许通用创建实现特定接口并具有通用构造函数的新类型。另外:

static void DoSomething<T>(T t) where T: IMyInterface1, IMyInterface2
{
    t.MethodOnIMyInterface1();
    t.MethodOnIMyInterface2();
}

interface IMyInterface1 
{
    void MethodOnIMyInterface1();
}     
interface IMyInterface2
{
    void MethodOnIMyInterface2();
}     
class MyClass: IMyInterface1, IMyInterface2 
{ 
    // Method implementations omitted for clarity
}

// Calling code
MyClass myclass'
DoSomething(myclass);  // Note that the compiler infers the type of T.

您可以在单个参数上要求多个接口,而无需 (1) 创建实现所有这些接口的新类型和 (2) 要求参数属于该类型。

正如@dcastro 在他/她的回答中指出的那样,泛型类型也可以告诉编译器要求类型相同。例如:

static void DoSomething<T>(T t1, T t2) where T: MyType
{
    // ...
}

class MyType {}
class MyType1: MyType {} 
class MyType2: MyType {} 

// Calling code
MyType1 myType1;
MyType2 myType2;
DoSomething<MyType>(myType1, myType2);

编译器要求 t1 和 t2 是同一类型,但可以是继承 MyType 的任何类型。这在自动化单元测试框架(例如 NUnit 或 MSTest)中非常有用,可用于通用相等性和比较检查。

【讨论】:

  • 最后关于强制相同类型的位是不正确的。这些中的任何一个都可以编译得很好DoSomething&lt;MyType&gt;(mytype1, mytype2); DoSomething((MyType)mytype1, mytype2); ...
  • @akton 感谢您的详细回答。我真的很感激提供的所有答案!我意识到我没有给出最好的例子,但你设法很好地回答了这个问题。再次感谢!
  • @Brandon 问题不在于事情是否会编译。泛型类型 (1) 使代码更易于阅读(尽管不是在 OP 的情况下)和 (2) 将更多检查从运行时转移到编译时间(通常通过替换强制转换)。在特定情况下,这不是最好的例子,但足以回答 OP 的问题。
  • 另外,如果我们有 where T : ISampleISample 一个接口,这将允许我们使用 structclass 的方法 T 的“值”。当我们在方法参数result 上调用接口ISample 的成员时,很酷的是即使T 是一个值类型(结构),当我们调用ISample 时我们也不会装箱result 上的成员(方法等)。如果结构有明确的接口实现,我们甚至可以在不装箱的情况下调用它们。
【解决方案2】:

大多数答案都提供了对涉及接口的泛型有用性的解释,这些接口似乎并不能真正解决您的实际问题。

事实是,对于您发布的示例,使用泛型方法没有任何好处。它实际上更糟,因为它会导致生成同一函数的多个实现,并在运行时略微增加代码大小。

【讨论】:

  • 我认为您提到的“多重实现”不适用于他的情况,因为Sample 必然是引用类型(实际上他告诉我们它是class)。对于引用类型,没有“多个实现”。除此之外,您可能是对的,在他的特定情况下没有太多好处。我们确实得到了一个额外的类型T(这是一个编译时类型,因此typeof(T) 不一定与result.GetType() 相同)。该方法可以使用该类型,例如var config = HelperClass&lt;T&gt;.GetConfig(); 之类的。
【解决方案3】:

在 voids 中,您总是可以使用接口作为参数来使多种类型工作,因此泛型在这里通常没有用处。

只有例外是对泛型的约束。我的意思不是这样的 其中T:IA,IB 因为这也可以通过同时实现 IA 和 IB 的接口来完成。然而,这在某些时候会变得令人厌烦,因为您将需要越来越多的接口。那么让我们看看“特殊约束”类和新的

public void AddNew(List<T> items) where T : new
{
    items.Add(new T());
}

如果方法改变了它的参数,类是有用的,这对结构不起作用

static void IncA<T>(T item) where T: class, IA
{
    item.A++;
}

泛型的真正强大之处在于方法具有泛型返回类型或像 List 这样的泛型类。您不想为您需要的每个 List 实现一个新类。

【讨论】:

    猜你喜欢
    • 2019-10-11
    • 1970-01-01
    • 1970-01-01
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多