将泛型结构转换为具有不同类型参数的相同泛型结构

本文关键字:结构 泛型 类型参数 转换 | 更新日期: 2023-09-27 18:33:15

假设我有一个基本的类层次结构,如下所示:

public abstract class BaseClass { }
public class X : BaseClass { }
public class Y: BaseClass { }

我有一个通用结构,如下所示:

public struct MyStruct<T>
  where T: BaseClass, new()
{
}

然后,我可以创建一个实例,如下所示:

var x = new MyStruct<X>();

现在我想在 MyStruct 上提供一个操作(构造函数或转换运算符(,它允许我将MyStruct<X>转换为MyStruct<Y>

MyStruct<Y> my = new MyStruct<X>();

当我编写构造函数时,如下所示:

public struct MyStruct<T>
    where T: BaseClass, new()
{
    public MyStruct(MyStruct<T2> value) 
        where T2: BaseClass, new()
    {
      ...
    }
}

编译器不明白我想做什么(似乎无法区分MyStruct<T>MyStruct<T2>(。

如何从MyStruct<T>内将MyStruct<X>转换为MyStruct<Y>

将泛型结构转换为具有不同类型参数的相同泛型结构

你不能在构造函数中这样做,但你应该能够在结构中编写一个转换方法,如下所示:

public struct MyStruct<T>
    where T: BaseClass, new()
{
    // Convert this instance of MyStruct<T> to a new MyStruct<TOut>
    public MyStruct<TOut> ToMyStruct<TOut>()
    {
        ...
    }
}

这将允许您编写:

struct2 = struct1.ToMyStruct<TOut>()

C# 没有泛型转换运算符

的概念;任何转换运算符(无论是隐式还是显式(都必须导入或导出完全由定义类型的泛型参数定义的类型。 这意味着Foo<T>可以定义与Bar<T>之间的转换运算符(反之亦然(,Foo<T,U>可以定义与Bar<U>之间的转换,但反之则不然。 这也意味着Foo<T>可以定义与'Bar之间的转换,但反之则不然。 遗憾的是,没有办法有一个转换运算符来导入或导出具有定义类型之外的泛型类型参数的类型,即使参数将以强制转换成功的方式进行约束。

所有这些意味着必须经常使用方法而不是运算符来执行转换(或者,就此而言,执行混合类型的操作(。 方法的泛型类型解析非常聪明(至少如果愿意包含默认的 null 虚拟参数(,但对于运算符来说,它非常有限。

顺便说一下,如果结构使用泛型类型参数的唯一目的是定义该类型的公共字段,那么理论上这样的结构应该可以支持协方差,而不考虑结构是否"可变",因为将KeyValuePair<FordFocus,SiameseCat>分配给KeyValuePair<Vehicle,Animal>将表示将FordFocus分配给Vehicle,将SiameseCat分配给Animal, 两者都是类型安全的。 但是,这将失败,因为所有盒装结构始终是可变的,并且类型的可变方面不能安全地支持协方差。

我使用以下方法使其工作:

public static implicit operator MyStruct<T>(MyStruct<X> value)
{
    return new MyStruct<T>(value);
}
public static implicit operator MyStruct<T>(MyStruct<Y> value)
{
    return new MyStruct<T>(value);
}
....

这仅限于已知类型(X、Y、...(,但让我编写以下代码:

MyStruct<X> x = new MyStruct<X>(...);
MyStruct<Y> y = x;