使用泛型对象初始化非泛型对象

3
有时我对C#泛型中的“T”不够理解。 我有一个泛型结构体。
public struct ValueWithUnit<T>
{
    public ValueWithUnit(T _value, Unit _unit)
    {
        Unit = _unit;
        Value = _value;
    }
    public Unit Unit { get; }
    public T Value { get; }
}

(Unit是一个枚举类型,T应该是数值型的,但没有可用于此目的的约束条件)。

对于WCF,我需要一个非泛型版本,其中Tdouble。 所以我想到了:

public struct DoubleValueWithUnit 
{
    public DoubleValueWithUnit(double _value, Unit _unit)
    {
        Unit = _unit;
        Value = _value;
    }
    public DoubleValueWithUnit(ValueWithUnit<T> _valueWithUnit)
    {
        Unit = _valueWithUnit.Unit;
        Value = Convert.ToDouble(_valueWithUnit.Value);
    }
    public Unit Unit { get; set; }
    public double Value { get; set; }
}

但是第二个构造函数无法编译:error CS0246:找不到类型或命名空间名称“T”... 而 Convert.ToDouble 报错: 无法解析方法'ToDouble(T)',候选项是...

我知道可以向泛型类添加转换方法:

    public DoubleValueWithUnit ToDoubleValueWithUnit()
    {
        return new DoubleValueWithUnit(Convert.ToDouble(Value), Unit);
    }

可以使用这种方法。但是,在非泛型类/结构中添加具有通用参数的构造函数是否有可能呢?


4
为什么不直接使用ValueWithUnit<double>而是使用DoubleValueWithUnit - Maarten
你想要做的事情是不可能的 - 然而,Maarten的建议可能是这里最好的解决方案。 - Rob
@Maarten 因为WCF与泛型的兼容性... - Bernhard Hiller
3个回答

2

我认为这个构造函数根本不应该存在:

public DoubleValueWithUnit(ValueWithUnit<T> _valueWithUnit)
{
    Unit = _valueWithUnit.Unit;
    Value = Convert.ToDouble(_valueWithUnit.Value);
}

为什么要将一个 ValueWithUnit<T> 转换为 DoubleValueWithUnit?对于某些值的 T,这是没有意义的。你如何将 BinaryFormatterForm 转换为 double?这些在编译时根本不应该被允许。

因此,你可以这样做:

public DoubleValueWithUnit(ValueWithUnit<double> _valueWithUnit)
{
    Unit = _valueWithUnit.Unit;
    Value = _valueWithUnit.Value;
}

或者完全删除构造函数。


“你为什么想要转换” - WCF 无法处理泛型。 "T" 实际上是数字,但没有 where T:numeric 可用。 - Bernhard Hiller
@BernhardHiller 我明白了。那我建议你为每种数字类型编写一个构造函数。 - Sweeper

0
在第二个例子中,T 没有被定义。因此,您不能在该结构的上下文中使用 T。
只需删除此构造函数即可:
public DoubleValueWithUnit(ValueWithUnit<T> _valueWithUnit)

由于您想将传递的任何内容转换为Double,请定义一个以对象作为输入的构造函数。在构造函数中尝试强制转换并在对象不可转换时抛出异常。

public DoubleValueWithUnit(object obj, Unit unit)
{
    Unit = unit;
    try
    {
       Value = Convert.ToDouble( obj );
    }
    catch( Exception )
    {
       throw new ArgumentException("Cannot convert to double", nameof(obj) );
    }        
}

在构造函数中抛出异常也不是一个好主意……只是提醒一下。 - kuskmen
@kuskmen 合同就是这样工作的。不要介意。(你说的不是真的) - Mauro Sampietro

0

我的当前解决方案是让结构体实现一个通用接口,该接口又继承了一个非通用接口:

public struct ValueWithUnit<T> : IValueWithUnit<T> {...}

public interface IValueWithUnit<out T> : IValueWithUnit // where T: number
{
    new T Value { get; }
}
public interface IValueWithUnit
{
    object Value { get; }
    Unit Unit { get; }
}

现在,我可以将 ValueWithUnit<T> 传递到(修改后的)构造函数中:
public DoubleValueWithUnit(IValueWithUnit _valueWithUnit)
{
    Unit = _valueWithUnit.Unit;
    Value = Convert.ToDouble(_valueWithUnit.Value);
}

我仍然不确定是否有更好的解决方案可行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接