C# 为什么在C语言中使用泛型约束#

C# 为什么在C语言中使用泛型约束#,c#,generics,constraints,C#,Generics,Constraints,我读了一篇关于MSDN的关于C#中泛型的优秀文章 我脑海中突然出现的问题是——我为什么要使用通用约束 例如,如果我使用如下代码: public class MyClass<T> where T : ISomething { } 公共类MyClass其中T:ISomething { } 我不能用ISomething切换该类中t的所有引用吗 使用这种方法有什么好处?首先,您可以在代码中为泛型类上的泛型方法调用ISomething中定义的方法。如果允许T是任何类型,那么这是不可能的(尽

我读了一篇关于MSDN的关于C#中泛型的优秀文章

我脑海中突然出现的问题是——我为什么要使用通用约束

例如,如果我使用如下代码:

public class MyClass<T> where T : ISomething
{
}
公共类MyClass其中T:ISomething
{
}
我不能用
ISomething
切换该类中
t
的所有引用吗


使用这种方法有什么好处?

首先,您可以在代码中为泛型类上的泛型方法调用ISomething中定义的方法。如果允许T是任何类型,那么这是不可能的(尽管您总是可以执行一些运行时强制转换)


因此,它允许您对T可以是什么强制执行编译时约束,并因此在编写代码时依赖这些约束—将运行时错误转化为编译时错误。

类型安全性。例如,假设您正在创建一个容器。您可以将某些内容传入该容器并以适当的形式检索它,而无需稍后通过参数化容器进行任何强制转换。您只是在定义您希望存储在容器中的对象类型的约束。

您会问,“我不能将这个类中
t
的所有引用都与
ISomething
切换吗?”因此我想您的意思是比较:

public class MyClass<T> where T : ISomething 
{ 
    public T MyProperty { get; set; }
}
在第二个示例中,
MyProperty
仅保证是
ISomething
的实例。在第一个示例中,
MyProperty
T
的任何内容,即使它是
ISomething
的特定子类型。考虑<代码>同构< <代码> >

的具体实现
public class MySomething : ISomething
{
    public string MyOtherProperty { get; set; }
}
MyClass myClass = new MyClass();
Console.WriteLine(myClass.MyProperty.MyOtherProperty); // Won't compile, no property "MyOtherProperty"
现在,如果我们使用第一个通用示例,我们可以:

MyClass<MySomething> myClass = new MyClass<MySomething>();
Console.WriteLine(myClass.MyProperty.MyOtherProperty);
另一方面,这些类型约束之所以有用,是因为您可以参考
MyProperty
(type
T
)并访问
ISomething
的成员。换句话说,如果
ISomething
声明如下:

public interface ISomething 
{
    public string SomeProperty { get; set; }
}

然后您可以访问
MyProperty.SomeProperty
。如果您省略了
其中的T:ISomething
,那么您将无法访问
SomeProperty
,因为
T
只会被认为是
对象类型的

这里有一个不同的示例,只需使用
列表

图像列表不是泛型的,但它只会在使用泛型的地方使用
IListElement
。现在想象你有一个类似这样的物体

class Element : IListElement
{
   public string Something { get; set; }
}
现在我可以做
list.Add(元素)与真正的
列表
没有区别。然而,当我检索数据时,情况就不同了,如果我使用使用
IListElement
的列表,那么我必须将我的数据放回原处,以便从中获取
内容。因此,我必须做:

string s = ((Element)list[0]).Something;
在使用泛型时,我只需执行以下操作:

string s = list[0].Something;

省去了很多麻烦,当然它比这更进一步了,但我认为你可以从中得到启发。

是的,你可以用ISomething代替T,但这将手动关闭普通类的泛型类型。它将不再是泛型类型。通过使用T,您可以将类型保持为打开状态,以使您想要的子类型尽可能多在不影响类型安全的情况下重用代码是此处的关键优势。例如,如果使用ISomething堆栈,可以将任何ISomething推送到堆栈上,但必须向下转换到ISomething的实际子类型才能使其发挥作用。向下投射会创建一个潜在的故障点,这在一般的
堆栈中是不存在的,其中T:ISomething

您的类的消费者可以从增加的类型安全性中获益

class Widget : IPokable { }

// No generics
Widget w = (Widget)list[0]; // cast can fail

// With generics
Widget w = list[0];
在没有泛型的情况下,如果列表包含
IPokable
对象,则仍然需要强制转换

您正在实现的类获得了在泛型对象上使用特定方法的好处

class PokableList<T> where T : IPokable {
    public T PokeAndGet() {
        currentObj.Poke();
        return currentObj;
    }
}
类PokableList,其中T:IPokable{
公共T PokeAndGet(){
currentObj.Poke();
返回电流OBJ;
}
}

这段youtube视频实际上证明了通用约束的重要性

下面是一个很长的文本答案

“泛型有助于将逻辑与数据类型解耦 附加具有任何逻辑的任何数据类型,以实现高重用性。”

但很多时候,某些逻辑只能附加到特定的数据类型

public class CompareNumeric<UNNKOWDATATYPE>
{
        public bool Compareme(UNNKOWDATATYPE v1, UNNKOWDATATYPE v2)
        {
            if (v1 > v2)
            {return true;}
            else
           {return false;}
        }
}
公共类比较
{
公共布尔比较器(UNNKOWDATATYPE v1,UNNKOWDATATYPE v2)
{
如果(v1>v2)
{返回true;}
其他的
{返回false;}
}
}
例如,上面是一个简单的泛型类,它在一个数字大于另一个数字时进行比较。现在“大于”和“小于”比较非常特定于数字数据类型。这种比较不能在字符串等非数字类型上进行

因此,如果一些人使用带有“int”类型的类,那么它是完全有效的

CompareNumeric<int> obj = new CompareNumeric<int>();
bool boolgreater = obj.Compare(10,20);
CompareNumeric<double> obj = new CompareNumeric<double>();
bool boolgreater = obj.Compare(100.23,20.45);
CompareNumeric obj=新的CompareNumeric();
bool boolgreater=obj.Compare(10,20);
如果有人再次将其与“double”数据类型一起使用,则完全有效

CompareNumeric<int> obj = new CompareNumeric<int>();
bool boolgreater = obj.Compare(10,20);
CompareNumeric<double> obj = new CompareNumeric<double>();
bool boolgreater = obj.Compare(100.23,20.45);
CompareNumeric obj=新的CompareNumeric();
bool boolgreater=obj.Compare(100.23,20.45);
但将字符串数据类型与此逻辑结合使用将导致不希望的结果。因此,我们想限制或约束哪些类型可以附加到泛型类,这是通过使用“泛型约束”实现的

CompareNumeric<string> obj = new CompareNumeric<string>();
bool boolgreater = obj.Compare(“interview”,”interviewer”);
CompareNumeric obj=新的CompareNumeric();
bool boolgreater=对象比较(“面试”、“面试官”);
可以通过在泛型类之后使用“WHERE”关键字指定数据类型来限制泛型类型,如下代码所示。现在,如果任何客户机尝试使用下面的类附加“string”数据类型,它将不允许,从而避免不希望的结果

public class CompareNumeric<UNNKOWDATATYPE> where UNNKOWDATATYPE : int, double
{

}