C# 如何从基类通用地实例化派生类

C# 如何从基类通用地实例化派生类,c#,class,oop,design-patterns,generics,C#,Class,Oop,Design Patterns,Generics,我扩展了本文中给出的单位转换器类: 这就是我现在拥有的: public abstract class UnitBase<TUnitType, TValueType> where TUnitType : struct, IComparable, IConvertible, IFormattable { protected static TUnitType BaseUnit; protected static TValueType BaseValue; priv

我扩展了本文中给出的单位转换器类: 这就是我现在拥有的:

public abstract class UnitBase<TUnitType, TValueType> where TUnitType : struct, IComparable, IConvertible, IFormattable
{
    protected static TUnitType BaseUnit;
    protected static TValueType BaseValue;

    private static ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>> ConversionsTo = new ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>>();

    private static ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>> ConversionsFrom = new ConcurrentDictionary<TUnitType, Func<TValueType, TValueType>>();

    public static TValueType Convert(TValueType value, TUnitType from, TUnitType to)
    {
        // If both From/To are the same, don't do any work.
        if (from.Equals(to))
            return value;

        // Convert into the base unit, if required.
        var valueInBaseUnit = from.Equals(BaseUnit)
                                ? value
                                : ConversionsFrom[from](value);

        // Convert from the base unit into the requested unit, if required
        var valueInRequiredUnit = to.Equals(BaseUnit)
                                ? valueInBaseUnit
                                : ConversionsTo[to](valueInBaseUnit);

        return valueInRequiredUnit;
    }

    protected static void RegisterConversion(TUnitType convertToUnit, Func<TValueType, TValueType> conversionTo, Func<TValueType, TValueType> conversionFrom)
    {
        if (!ConversionsTo.TryAdd(convertToUnit, conversionTo))
            throw new ArgumentException("Already exists", "convertToUnit");
        if (!ConversionsFrom.TryAdd(convertToUnit, conversionFrom))
            throw new ArgumentException("Already exists", "convertToUnit");
    }

    public static string GetUnit(TUnitType unit)
    {
        var type = typeof(TUnitType);
        if (!type.IsEnum)
        {
            throw new ArgumentException();
        }

        return Enums.GetEnumDescription(unit as Enum);
    }

    public TValueType InUnit(TUnitType unit)
    {
        return Convert(BaseValue, BaseUnit, unit);
    }
}
…而不必在每个具体类中实现FromUnit。因为它是一个静态方法,所以我不能使用接口强制实现。我可以在具体类中有一个公共构造函数,并有如下内容:

public static T FromUnit<T>(TValueType value, TUnitType unit) where T : new()
{
    BaseValue = Convert(value, unit, BaseUnit);
    return new T();
}

…将泛型FromUnit放入基类。

为什么不将FromUnit实现推送到UnitBase本身:

    public static TValueType FromUnit(TValueType value, TUnitType unit)
    {
        return Convert(value, BaseUnit, unit);
    }
“not so nice”解决方案中的
类型参数可能看起来是多余的,但实际上并非如此。当你写作时

Temperature temperature = Temperature.FromUnit<Temperature>(10, TemperatureUnit.Celcius);
Temperature-Temperature=Temperature.from单位(10,TemperatureUnit.Celcius);
代码实际上被翻译为

Temperature temperature = UnitBase<TemperatureUnit, double>.FromUnit<Temperature>(10, TemperatureUnit.Celcius);
Temperature-Temperature=UnitBase.FromUnit(10,TemperatureUnit.Celcius);

编译器非常好,允许您使用
Temperature
访问该方法。因为它实际上调用的是
UnitBase.FromUnit()
,所以它不知道您实际上想要使用
Temperature
,这就是为什么您必须提供它作为一个附加类型参数的原因。

这正是我想要做的,但是对于FromUnit,我想要返回具体类的实例(例如Temperature),而不是TValueType(例如双倍)。您的问题中不应该有xml注释,仅供参考。这会使您的问题变得过长。好的,我删除了xml注释。感谢您的提示。好的,额外的
类型参数可能没那么糟糕,但我可能会坚持在每个子类中使用FromUnit实现,这样我就可以执行
温度=tTemperature.FromUnit(10,TemperatureUnit.Celcius);
我将能够保持每个子类的构造函数私有。无论如何,谢谢!
public static Temperature FromUnit(double value, TemperatureUnit unit)
{
    return new Temperature(Convert(value, unit, BaseUnit));
}

public static Pressure FromUnit(double value, PressureUnit unit)
{
    return new Pressure(Convert(value, unit, BaseUnit));
}

public static Speed FromUnit(double value, SpeedUnit unit)
{
    return new Speed(Convert(value, unit, BaseUnit));
}

...
    public static TValueType FromUnit(TValueType value, TUnitType unit)
    {
        return Convert(value, BaseUnit, unit);
    }
Temperature temperature = Temperature.FromUnit<Temperature>(10, TemperatureUnit.Celcius);
Temperature temperature = UnitBase<TemperatureUnit, double>.FromUnit<Temperature>(10, TemperatureUnit.Celcius);