如何基于类上的泛型类型约束泛型方法上的类型

时间:2021-05-06 15:36:45

标签: c# generics constraints

我正在尝试实现一个泛型方法,但需要将一个泛型类型(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 是不正确的。

3 个答案:

答案 0 :(得分:2)

您可以使用 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

答案 1 :(得分:1)

因此,您需要一个基于 T1 的类型。您不能直接执行此操作,但可以执行以下操作,但在使用该方法时必须通过指定类型参数来证明关系。也可能有办法克服限制。

基本上,引入一个“是”T1 的类型参数,然后你可以引入一个作为该类型基础的类型参数。最终看起来像这样:

public class SomeClass<TOriginal> {
   public void SomeMethod<TSubstitute, TBase>(
      TOriginal someParameter
   ) where TSubstitute : TOriginal, TBase {
        TBase someVariable = (TBase)(TSubstitute)someParameter;

        ...
    }
}

使用时,TOriginalTSubstitute 通常是相同的类型。这并没有明确说 TOriginalTBase 的后代,但它确实说存在一些其他类型的 TSubstitute 是两者的后代(并且“后代”包括相同输入)。

答案 2 :(得分:0)

听起来您想确保 T2 以某种方式可强制转换或可转换为 T1,您可能需要考虑使用两个对象之间的公共接口作为 { {1}}。

这是一个简短的例子:

SomeMethod