C# 将约束泛型类型传递给非泛型方法

C# 将约束泛型类型传递给非泛型方法,c#,generics,.net-4.0,casting,C#,Generics,.net 4.0,Casting,为什么我不能传递这个类的实例 class Item<T> where T : Thing { } …在这种方法中: void DoSomething(Item<Thing> item); 由于我已将项目约束为一个项目,因此在将项目发送到DoSomething之前进行强制转换应该是安全的,但是为什么框架不能处理这个问题呢?想象一下 class Derived : Thing {} 项目不可分配给项目。 class Derived : Thing {} 项不可分配给项

为什么我不能传递这个类的实例

class Item<T> where T : Thing { }
…在这种方法中:

void DoSomething(Item<Thing> item);
由于我已将项目约束为一个项目,因此在将项目发送到DoSomething之前进行强制转换应该是安全的,但是为什么框架不能处理这个问题呢?

想象一下

class Derived : Thing {}
项目不可分配给项目。

class Derived : Thing {}

项不可分配给项。

您需要在方法声明中更具体一些,如下所示

void DoSomething<T>(Item<T> item)
    where T : Thing
{
    // now your method knows that T must be of time Thing and you can use it
}

您需要在方法声明中更具体一些,如下所示

void DoSomething<T>(Item<T> item)
    where T : Thing
{
    // now your method knows that T must be of time Thing and you can use it
}

假设你有一门课:

public class SomeOtherThing : Thing { }
无法将项目强制转换为项目。它们不一样

让我们假设该项看起来如下所示:

public class Item<T>
{
    public T Value { get; set; }
}
void DoSomething<T>(Item<T> item)
    where T : Thing
{    }
如果您将一个项目传递给DoSomething,您现在刚刚为Value分配了一个新的对象,但Value是SomeOtherThing类型的属性,则无法为其设置Thing对象。这将破坏类型系统。编译器知道这是一个选项。由于这一点以及其他许多具有相同基本问题的操作,无法将项目强制转换为项目

那么,你能做什么

好吧,如果你控制剂量测量的定义,也许它也应该是通用的

如果DoSomething如下所示:

public class Item<T>
{
    public T Value { get; set; }
}
void DoSomething<T>(Item<T> item)
    where T : Thing
{    }

然后您可以用一个项目调用它,因为以前可能会导致问题的操作在DoSomething中不再有效。

假设您有一个类:

public class SomeOtherThing : Thing { }
无法将项目强制转换为项目。它们不一样

让我们假设该项看起来如下所示:

public class Item<T>
{
    public T Value { get; set; }
}
void DoSomething<T>(Item<T> item)
    where T : Thing
{    }
如果您将一个项目传递给DoSomething,您现在刚刚为Value分配了一个新的对象,但Value是SomeOtherThing类型的属性,则无法为其设置Thing对象。这将破坏类型系统。编译器知道这是一个选项。由于这一点以及其他许多具有相同基本问题的操作,无法将项目强制转换为项目

那么,你能做什么

好吧,如果你控制剂量测量的定义,也许它也应该是通用的

如果DoSomething如下所示:

public class Item<T>
{
    public T Value { get; set; }
}
void DoSomething<T>(Item<T> item)
    where T : Thing
{    }

然后,您可以使用项调用它,因为以前可能导致问题的操作在DoSomething中不再有效。

您的问题是您的方法特定于项,而项不是有效的参数。C不支持泛型类协方差。你有几个选择

最简单的方法就是简单地使方法泛化,并为它添加一个约束。这将是第一个明智的做法

void DoSomething<T>(Item<T> item) where T : Thing
{
}
您的方法只需要期望项,您就可以使用它了。但是,如果你有一个特定的需求来处理这个东西,它就有点微妙了,你需要根据需要进行转换,但是你也面临着这样的可能性:有人传递了一个实例,而这个实例不是一个项目,其中t是一个东西

另一种选择是不使用方法的签名,而是从类转换为接口,这允许您使用协方差。NET 4.0支持接口和委托类型的协变/逆变

interface Item<out T> 
{
    T Get();
    // void Set(T foo); // invalid  
}

同样,这里的问题是1您显然需要更改您的类型,但2您将仅限于在输出位置公开T。请注意,支持Get方法。SetT方法不是,因为T是一个输入,这使得接口不协变有效。想象一下传入一个项,并且您的方法尝试用其他东西调用Set。两者都是事情,但显然第二个不适合第一个。因此,如果您需要同时支持T作为输出和输入,那么就不能使用这种方法

问题是您的方法特定于Item,而Item不是有效的参数。C不支持泛型类协方差。你有几个选择

最简单的方法就是简单地使方法泛化,并为它添加一个约束。这将是第一个明智的做法

void DoSomething<T>(Item<T> item) where T : Thing
{
}
您的方法只需要期望项,您就可以使用它了。但是,如果你有一个特定的需求来处理这个东西,它就有点微妙了,你需要根据需要进行转换,但是你也面临着这样的可能性:有人传递了一个实例,而这个实例不是一个项目,其中t是一个东西

另一种选择是不使用方法的签名,而是从类转换为接口,这允许您使用协方差。NET 4.0支持接口和委托类型的协变/逆变

interface Item<out T> 
{
    T Get();
    // void Set(T foo); // invalid  
}
同样,这里的问题是1您显然需要更改您的类型,但2您将仅限于在输出位置公开T。请注意,支持Get方法。SetT方法不是,因为T是一个输入,这使得接口不协变有效。想象一下传入一个项,并且您的方法尝试用其他东西调用Set。两者都是事情,但显然第二个不适合第一个。所以如果你需要的话
支持T作为输出和输入,您不能使用此方法

谢谢,我经常忘记协方差等。这是一个很好的提醒!谢谢,我经常忘记协方差等。这是一个很好的提醒!谢谢我的项目实际上是一个项目和一个项目,所以我只是扩展并通过了一个项目。谢谢。我的项目实际上是一个项目和一个项目,所以我只是扩展并通过了一个项目。