将类型参数约束为基本类型

我知道如何强制类型参数成为另一种类型的类型:

public interface IMapping { public void Serialize(T3 obj) where T3 : T2; } ... var mapping = MapManager.Find(); mapping.Serialize(new TonkaTruck()); 

有没有办法强制类型参数成为另一种类型的类型?

 public interface IMapping { public void IncludeMappingOf() where T2 : T1; // <== doesn't work } ... var mapping = MapManager.Find(); // Truck inherits Vehicle // Would like compiler safety here: mapping.IncludeMappingOf(); mapping.Serialize(new TonkaTruck()); 

目前,我必须在运行时使用IsSubclassOf中的IncludeMappingOf来比较T1和T2。 编译安全的解决方案更可取。 有任何想法吗?

编辑:改变示例,以减少设计臭。

注意:链接的问题非常相似,但没有给出合适的答案。 希望这个问题也会对这个问题有所启发。

编辑#2:

更简单的例子:

 public class Holder { public T2 Data { get; set; } public void AddDataTo(ICollection coll) //where T2 : T1 // <== doesn't work { coll.Add(Data); // error } } ... var holder = new Holder { Data = new TonkaTruck() }; var list = new List(); holder.AddDataTo(list); 

编译器:参数类型’T2’不能赋值参数类型’T1’。 是的我知道,我正在尝试让编译器只允许T2可分配给参数类型T1的情况!

您可以使用扩展方法来接近您想要的。 使用您的持有者示例,它将是:

 public class Holder { public T2 Data { get; set; } } public static class HolderExtensions { public static void AddDataTo(this Holder holder, ICollection coll) where T2 : T1 { coll.Add(holder.Data); } } 

然后,允许您的示例调用代码编译而不会出现错误:

 var holder = new Holder { Data = new TonkaTruck() }; var list = new List(); holder.AddDataTo(list); 

映射示例因其是接口而变得复杂。 如果无法从现有接口实现扩展方法,则可能需要向接口添加实现方法。 这意味着您仍然需要运行时检查,但调用者可以获得良好的语法和编译时检查。 这将是这样的:

 public interface IMapping { void IncludeMappingOf(Type type); } public static class MappingExtensions { public static void IncludeMappingOf(this IMapping mapping) where T2 : T1 { mapping.IncludeMappingOf(typeof(T1)); } } 

不幸的是, IncludeMappingOf没有T1类型的参数,因此无法推断出类型参数。 调用它时,您必须指定这两种类型:

 var mapping = MapManager.Find(); mapping.IncludeMappingOf(); mapping.Serialize(new TonkaTruck()); 

通常可以通过更改API以包含参数(即truckMapping.IncludeMappingOf(vehicleMapping) ),更改参数所在的方法/类或创建链的流畅API(即mapping.Of().Include() )。

虽然w0lf的答案提供了直接的解决方案,但我想提供一些背景解释。

当你写类似的东西

 class C where A : B 

要么

 void F() where A : B 

formsA : B的约束必须将A作为声明的类,接口,方法等的generics类型参数之一。

您面临的错误不是因为您在冒号的右侧放置了当前声明的generics类型参数(这是合法的) – 这是因为您已经放置了外部声明的generics类型参数(不是当前的声明)在结肠的左侧。

如果要在某个声明上形成约束A : B ,则必须在该声明中引入A ,并且A的范围必须小于或等于B的范围。 这是一个实用的语言限制的原因是,对于任何generics类型参数T ,它将关于类型T约束的任何推理隔离到引入T的单个声明。

在类(接口)级别声明generics类型和generics约束:

 public interface IMapping where T2 : T1 { void IncludeMapping(IMapping otherMapping); }