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?

+3


source to share


3 answers


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.

+2


source


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

      

0


source


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.

0


source







All Articles