问题描述
我正在尝试实现一个泛型方法,但需要将一个泛型类型(T1 - 在类中定义)的对象转换为另一种泛型(在方法中定义的 T2)。除了在类上定义 T2(我不想这样做,因为并不总是需要它),还有其他方法可以实现吗?
我在做这样的事情:
public class SomeClass<T1>
{
public void SomeMethod<T2>(T1 someParameter) where T1 : T2
{
T2 someVariable = (T2) someParameter;
}
}
似乎约束只会以错误的方式起作用,即 where T2:T1
起作用(但对于我的目的显然是错误的),但 where T1:T2
不起作用。
更新 我需要将 T1 转换为 T2 的原因是我在数据库插入方法中使用结果,该方法使用接口上的反射来确定要插入的列。例如,该接口用于防止尝试插入计算列。所以 T2 将是这个接口,而 T1 将是一个原始对象(它会有更多的字段)。因此,转换 T2:T1 是不正确的。
解决方法
您可以使用 is
(或 as
)关键字来做到这一点* - T2
上唯一的必要约束是它是一个 class
public class SomeClass<T1>
{
public void SomeMethod<T2>(T1 someParameter) where T2 : class
{
if(!(someParameter is T2 t2))
{
throw new Exception("Invalid type");
}
Console.WriteLine($"Hello from {t2}");
}
}
现场示例:https://dotnetfiddle.net/C5Brhn
(* 很好,虽然它是运行时检查,而不是您的原始问题暗示的编译时检查)
使用 .NET5,您可以使用更好的表达式 is not
public class SomeClass<T1>
{
public void SomeMethod<T2>(T1 someParameter) where T2 : class
{
if(someParameter is not T2 t2)
{
throw new Exception("Invalid type");
}
Console.WriteLine($"Hello from {t2}");
}
}
注意基于此评论
T2 是 T1 上字段的子集,所以 T1 是从 T2 派生出来的
我使用过 T1=Lion 和 T2=Animal
,因此,您需要一个基于 T1
的类型。您不能直接执行此操作,但可以执行以下操作,但在使用该方法时必须通过指定类型参数来证明关系。也可能有办法克服限制。
基本上,引入一个“是”T1
的类型参数,然后你可以引入一个作为该类型基础的类型参数。最终看起来像这样:
public class SomeClass<TOriginal> {
public void SomeMethod<TSubstitute,TBase>(
TOriginal someParameter
) where TSubstitute : TOriginal,TBase {
TBase someVariable = (TBase)(TSubstitute)someParameter;
...
}
}
使用时,TOriginal
和 TSubstitute
通常是相同的类型。这并没有明确说 TOriginal
是 TBase
的后代,但它确实说存在一些其他类型的 TSubstitute
是两者的后代(并且“后代”包括相同输入)。
听起来您想确保 T2
以某种方式可强制转换或可转换为 T1
,您可能需要考虑使用两个对象之间的公共接口作为 { {1}}。
这是一个简短的例子:
SomeMethod