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

时间:2013-09-28 22:54:14

标签: c# generics struct

假设我有一个基本的类层次结构:

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<X>内将MyStruct<Y>转换为MyStruct<T>

3 个答案:

答案 0 :(得分:3)

您不能在构造函数中执行此操作,但您应该能够在结构中编写转换方法,例如:

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>()

答案 1 :(得分:2)

C#没有通用转换运算符的概念;任何转换运算符,无论是隐式还是显式,都必须导入或导出由定义类型的泛型参数完全定义的类型。这意味着Foo<T>可以定义转换运算符到Bar<T>或从Foo<T,U>定义(反之亦然),Bar<U>可以定义与Foo<T>之间的转换,但反之亦然。这也意味着KeyValuePair<FordFocus,SiameseCat>可以定义与Bar的转换,但反之亦然。遗憾的是,没有办法可以使用转换运算符来导入或导出类型超出定义类型的泛型类型参数的类型,即使参数的约束方式使得转换成功。

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

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

答案 2 :(得分:2)

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

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;