[英]Constrain type parameter to a base type
我知道如何强制类型参数成为另一种类型的子类型:
public interface IMapping<T2>
{
public void Serialize<T3>(T3 obj)
where T3 : T2;
}
...
var mapping = MapManager.Find<Truck>();
mapping.Serialize(new TonkaTruck());
有没有办法强制类型参数成为另一种类型的超类型?
public interface IMapping<T2>
{
public void IncludeMappingOf<T1>()
where T2 : T1; // <== doesn't work
}
...
var mapping = MapManager.Find<Truck>();
// Truck inherits Vehicle
// Would like compiler safety here:
mapping.IncludeMappingOf<Vehicle>();
mapping.Serialize(new TonkaTruck());
目前,我必须在运行时使用IsSubclassOf
中的IncludeMappingOf
来比较T1和T2。 编译安全的解决方案更可取。 有任何想法吗?
编辑:改变示例,以减少设计臭。
注意:链接的问题非常相似,但没有给出合适的答案。 希望这个问题也会对这个问题有所了解。
编辑#2:
更简单的例子:
public class Holder<T2>
{
public T2 Data { get; set; }
public void AddDataTo<T1>(ICollection<T1> coll)
//where T2 : T1 // <== doesn't work
{
coll.Add(Data); // error
}
}
...
var holder = new Holder<Truck> { Data = new TonkaTruck() };
var list = new List<Vehicle>();
holder.AddDataTo(list);
编译器:参数类型'T2'不能赋值参数类型'T1'。 是的我知道,我正在尝试让编译器只允许T2可分配给参数类型T1的情况!
虽然w0lf的答案提供了直接的解决方案,但我想给出一些背景解释。
当你写的东西像
class C<A> where A : B
要么
void F<A>() where A : B
形式A : B
的约束必须将A
作为声明的类,接口,方法等的泛型类型参数之一。
您面临的错误不是因为您在冒号的右侧放置了当前声明的泛型类型参数(这是合法的) - 这是因为您已经放置了外部声明的泛型类型参数(不是当前声明)在结肠的左侧。
如果要在某个声明上形成约束A : B
,则必须在该声明中引入A
,并且A
的范围必须小于或等于B
的范围。 究其原因,这是一个务实的语言的限制是,对于任何泛型类型参数T
,它隔离了关于类型约束任何推理T
到单个声明T
被引入。
在类(接口)级别声明泛型类型和泛型约束:
public interface IMapping<T1, T2> where T2 : T1
{
void IncludeMapping(IMapping<T1, T2> otherMapping);
}
您可以使用扩展方法来接近您想要的。 使用您的持有者示例将是:
public class Holder<T2>
{
public T2 Data { get; set; }
}
public static class HolderExtensions
{
public static void AddDataTo<T2, T1>(this Holder<T2> holder, ICollection<T1> coll)
where T2 : T1
{
coll.Add(holder.Data);
}
}
然后,允许您的示例调用代码编译而不会出现错误:
var holder = new Holder<Truck> { Data = new TonkaTruck() };
var list = new List<Vehicle>();
holder.AddDataTo(list);
映射示例因为它是一个接口而变得复杂。 如果无法从现有接口实现扩展方法,可能需要向接口添加实现方法。 这意味着您仍然需要运行时检查,但调用者可以获得良好的语法和编译时间检查。 这将是这样的:
public interface IMapping<T2>
{
void IncludeMappingOf(Type type);
}
public static class MappingExtensions
{
public static void IncludeMappingOf<T2, T1>(this IMapping<T2> mapping)
where T2 : T1
{
mapping.IncludeMappingOf(typeof(T1));
}
}
遗憾的是, IncludeMappingOf
没有T1
类型的参数,因此无法推断出类型参数。 调用它时,您必须指定这两种类型:
var mapping = MapManager.Find<Truck>();
mapping.IncludeMappingOf<Truck, Vehicle>();
mapping.Serialize(new TonkaTruck());
通常可以通过更改API以包含参数(即truckMapping.IncludeMappingOf(vehicleMapping)
),更改参数所在的方法/类或创建链的流畅API(即mapping.Of<Vehicle>().Include()
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.