Initialize a non-shared object with a shared object
Sometimes I don't get these T
from C # Generics correctly. I have a general structure
public struct ValueWithUnit<T>
{
public ValueWithUnit(T _value, Unit _unit)
{
Unit = _unit;
Value = _value;
}
public Unit Unit { get; }
public T Value { get; }
}
( Unit
- it is enum
, T
must be numeric, but for this purpose there are no restrictions).
For WCF, I need a non-generic version, c T
double
. So I thought:
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; }
}
But the second constructor doesn't compile:
error CS0246: The type or namespace name 'T' could not be found ...
and Convert.ToDouble complains about
Cannot resolve method 'ToDouble(T)' Candidates are...
I know that I can add a conversion method to the generic class:
public DoubleValueWithUnit ToDoubleValueWithUnit()
{
return new DoubleValueWithUnit(Convert.ToDouble(Value), Unit);
}
It works. But is it possible to add a shared parameter constructor to a non-shared class / struct?
source to share
I don't think this constructor should exist at all:
public DoubleValueWithUnit(ValueWithUnit<T> _valueWithUnit)
{
Unit = _valueWithUnit.Unit;
Value = Convert.ToDouble(_valueWithUnit.Value);
}
Why do you want to convert ValueWithUnit<T>
to DoubleValueWithUnit
? For some values T
it doesn't make sense. How do you convert BinaryFormatter
to double
? Or a Form
before double
? It just shouldn't be allowed at compile time.
So, you either do this:
public DoubleValueWithUnit(ValueWithUnit<double> _valueWithUnit)
{
Unit = _valueWithUnit.Unit;
Value = _valueWithUnit.Value;
}
Or remove the constructor together.
source to share
In the second example, T is simply undefined. Therefore, you cannot use T in the context of this structure.
Just remove this constructor:
public DoubleValueWithUnit(ValueWithUnit<T> _valueWithUnit)
Since you want to convert anything passed to Double, define a constructor that takes as input. In the constructor, try throwing and throwing an exception if the object doesn't convert.
public DoubleValueWithUnit(object obj, Unit unit)
{
Unit = unit;
try
{
Value = Convert.ToDouble( obj );
}
catch( Exception )
{
throw new ArgumentException("Cannot convert to double", nameof(obj) );
}
}
source to share
My current solution is to have a structure that implements a generic interface, which in turn inherits from a non-generic interface:
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; }
}
Now I can pass ValueWithUnit<T>
to the constructor (modified):
public DoubleValueWithUnit(IValueWithUnit _valueWithUnit)
{
Unit = _valueWithUnit.Unit;
Value = Convert.ToDouble(_valueWithUnit.Value);
}
However, I am not sure if the best solutions are possible.
source to share