2017-05-30 41 views
3

有時候,我真不明白那些T C#的泛型的權利。我有一個通用的結構初始化非通用對象與通用對象

public struct ValueWithUnit<T> 
{ 
    public ValueWithUnit(T _value, Unit _unit) 
    { 
     Unit = _unit; 
     Value = _value; 
    } 
    public Unit Unit { get; } 
    public T Value { get; } 
} 

UnitenumT應該是數字,但沒有可用於該目的的約束)。

對於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: The type or namespace name 'T' could not be found ...和Convert.ToDouble與 Cannot resolve method 'ToDouble(T)' Candidates are...

抱怨我知道我可以添加一個轉換方法泛型類:

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

工程。但有沒有可能添加一個具有泛型參數的構造函數到非泛型類/結構?

+4

你爲什麼不只是使用'ValueWithUnit '而不是DoubleValueWithUnit'的'? – Maarten

+0

你試圖做什麼[是不可能的(https://開頭計算器。com/questions/700966/generic-type-in​​-constructor) - 但是,Maarten的建議可能是這裏最好的解決方案 – Rob

+0

@Maarten,因爲WCF與​​泛型兼容...... –

回答

0

在第二個例子中,T是根本無法限定。所以你不能在該結構的上下文中使用T.

只是刪除此構造函數:

public DoubleValueWithUnit(ValueWithUnit<T> _valueWithUnit) 

既然你想什麼傳遞給雙轉換,定義構造函數作爲輸入的對象。在構造函數中,如果對象不可轉換,則嘗試轉換並拋出異常。

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

在構造函數中拋出異常也不是一個好主意。只是通知。 – kuskmen

+0

@kuskmen合同正是這樣工作的。別介意。 (你說的不是真的) – sam

2

我不認爲這個構造函數應該存在:

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

你爲什麼要到ValueWithUnit<T>轉換爲DoubleValueWithUnit?有些值爲T,這是沒有意義的。你如何將BinaryFormatter轉換爲double?或者一個Formdouble?這些在編譯時不應該被允許。

所以,你做這一點:

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

或刪除構造都在一起。

+0

「你爲什麼要轉換」 - WCF不適應泛型。 「T」是事實上的數字,但是沒有「where T:numeric」可用。 –

+0

@BernhardHiller我明白了。然後我建議你爲每個數字類型編寫一個構造函數。 – Sweeper

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); 
} 

不過我不知道是否有可能更好的解決方案。