简体   繁体   English

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

[英]How can I constrain a type on a generic method based on a generic type on the class

I am trying to implement a generic method but need to cast an object of one generic type (T1 - defined on the class) to another generic type (T2 defined on the method).我正在尝试实现一个泛型方法,但需要将一种泛型类型(T1 - 在类上定义)的 object 转换为另一种泛型类型(在方法上定义的 T2)。 Other than defining T2 on the class (which I'd rather not because it won't always be needed), is there a way of achieving this?除了在 class 上定义 T2 (我不想这样做,因为它并不总是需要)之外,有没有办法实现这一点?

I'm after something like this:我追求的是这样的:

public class SomeClass<T1>
{
    public void SomeMethod<T2>(T1 someParameter) where T1 : T2
    {
        T2 someVariable = (T2) someParameter;
    }
}

It seems the constraint will only work the wrong way around, that is where T2:T1 works (but is obviously wrong for my purpose), but where T1:T2 doesn't.似乎约束只会以错误的方式起作用,这就是where T2:T1起作用的地方(但对于我的目的来说显然是错误的),但where T1:T2没有。

update The reason I need to cast T1 to T2, is I use the result in a database insert method which uses reflection on the Interface to determine what columns to insert into.更新我需要将 T1 转换为 T2 的原因是我在数据库插入方法中使用结果,该方法使用接口上的反射来确定要插入哪些列。 The interface is used to prevent trying to insert into computed columns for instance.例如,该接口用于防止尝试插入计算列。 So T2 would be this interface whereas T1 would be an original object (which would have more fields).所以 T2 将是这个接口,而 T1 将是一个原始的 object (它将有更多的字段)。 Hence casting T2:T1 would not be correct.因此,铸造 T2:T1 是不正确的。

You can do this fine* with is (or as ) keyword - the only constraint nexcessary on T2 is that it is a class您可以使用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}");
    }
}

Live example: https://dotnetfiddle.net/C5Brhn现场示例: https://dotnetfiddle.net/C5Brhn

(* fine, although it is a runtime check, not the compile-time check your original question hinted at) (*很好,虽然它是运行时检查,而不是编译时检查你原来的问题暗示)

With .NET5 you can use a better expression is not使用 .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}");
    }
}

Note that based on this comment请注意,基于此评论

T2 is a subset of the fields on T1 so it is T1 that derives from T2 T2 是 T1 上字段的子集,因此 T1 派生自 T2

I have used T1=Lion and T2=Animal我用过 T1=Lion 和 T2=Animal

So, you want a type that is a base of T1 .因此,您需要一个基于T1的类型。 You can't do that directly, but you could do the following, though you would have to prove the relationship when using the method by specifying the type arguments.您不能直接执行此操作,但可以执行以下操作,但在使用该方法时必须通过指定类型 arguments 来证明关系。 There may also be ways to defeat the constraint.也可能有一些方法可以克服约束。

Basically, introduce a type parameter that "is a" T1 , and then you can introduce a type parameter that is a base of that type.基本上,引入一个“是” T1的类型参数,然后您可以引入一个作为该类型基础的类型参数。 This ends up looking like this:这最终看起来像这样:

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

        ...
    }
}

When using it, TOriginal and TSubstitute will usually be the same type.使用它时, TOriginalTSubstitute通常是同一类型。 This doesn't explicitly say that TOriginal is descended from TBase , but it does say there exists some other type TSubstitute that is descended from both (and 'descended from' includes being the same type).这并没有明确说TOriginalTBase的后代,但它确实说存在一些其他类型TSubstitute是两者的后代(并且“后代”包括相同的类型)。

It sounds like you want to ensure that T2 is in some way castable or convertible to T1 , you may want to consider the use of a common interface between the two objects as a constraint for SomeMethod .听起来您想确保T2以某种方式可转换或可转换为T1 ,您可能需要考虑在两个对象之间使用公共接口作为SomeMethod的约束。

Heres a short example:这是一个简短的例子:

public interface ISomeInterface
{

}

public class SomeBaseClass : ISomeInterface
{

}

public class SomeClass<T1> where T1 : SomeBaseClass
{
    public void SomeMethod<T2>(T1 someParameter) where T2 : ISomeInterface
    {
        if (someParameter is T2 commonInterfacedObject)
        {
            T2 someVariable = commonInterfacedObject;
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM