创建类的最有效方法是在派生类中具有较小的方差

本文关键字:方差 有效 方法 创建 派生 | 更新日期: 2023-09-27 18:14:39

我有一个包含许多功能的类,称为Record。在系统中存在两种基本类型的记录,一种是主键为uint,另一种是主键为Guid

Record类包含我需要的所有特性,除了一个属性。Record.ID允许开发人员将当前主键读取为正确类型(uintGuid)。

为了实现这一点,我必须创建三个这样的类(简化示例):
class Record {
    ... lots of code ...
}
class RecordInt : Record {
     public uint ID { get; set; }
}
class RecordGuid : Record {
     public Guid ID { get; set; }
}

这工作正常,但它引入了一个问题,即数据模型不能仅仅创建一个通用的Record实例。他们必须知道派生类是期望RecordInt还是RecordGuid。所以我给模型添加了一个模板参数,就像这样。

class abstract class Model<T> : were T : Record, new()
{
   ... lots of generic code that uses T ...
   // example
   public List<T> Find(...) { 
      .. find a record ...
      return new List<T>(); 
   }
}

这给我带来了比仅仅拥有两个Record类型的好处更多的问题。现在,当我实例化一个模型时,代码必须知道需要什么类型的Record。如果这发生在一个应该是泛型的部分,那么我必须添加另一个模板参数。

我发现一段时间后开始有很多方法使用模板参数。只是为了将该类型传递给Model<RecordGuid>,有时我必须在真正需要它的代码之前将模板参数传递给几个方法调用链。

有没有比我现在做的更有效的模式?

编辑:

Model使用模板参数的一个原因是它需要有返回Record集合的方法。在c#中,你不能将List<Record>转换为List<RecordGuid>,所以我不得不使用一个模板参数作为List<T>的返回类型。

创建类的最有效方法是在派生类中具有较小的方差

我决定创建一个新类来表示主键,并让这个类控制该ID的Type状态。

这将允许我只创建一个类来表示Record,而该类可以支持uintGuid主键。这也意味着Model类不再需要模板参数,这导致依赖于Model的其他源代码也不需要模板参数。

这是我使用的PrimaryValue类。

/// <summary>
/// Used to store the value of the primary key for a table.
/// </summary>
public sealed class PrimaryValue
{
    /// <summary>
    /// The raw value
    /// </summary>
    private object _value;
    /// <summary>
    /// The required type.
    /// </summary>
    private Type _type;
    /// <summary>
    /// True if a Guid type.
    /// </summary>
    public bool IsGUID
    {
        get
        {
            return _type == typeof(Guid);
        }
    }
    /// <summary>
    /// Type if a uint type.
    /// </summary>
    public bool IsInteger
    {
        get
        {
            return _type == typeof(uint);
        }
    }
    /// <summary>
    /// True if the value is empty.
    /// </summary>
    public bool Empty
    {
        get
        {
            if (_type == typeof(uint))
            {
                return (uint)_value == 0;
            }
            return (Guid)_value == Guid.Empty;
        }
    }
    /// <summary>
    /// Constructor
    /// </summary>
    public PrimaryValue(Type pType)
    {
        _type = pType;
        if (pType == typeof(uint))
        {
            _value = 0;
        }
        else if (pType == typeof(Guid))
        {
            _value = Guid.Empty;
        }
        else
        {
            throw new ModelException("Type not supported by PrimaryValue.");
        }
    }
    /// <summary>
    /// UINT constructor.
    /// </summary>
    public PrimaryValue(uint pValue)
    {
        _value = pValue;
        _type = typeof(uint);
    }
    /// <summary>
    /// GUID constructor
    /// </summary>
    public PrimaryValue(Guid pValue)
    {
        _value = pValue;
        _type = typeof(Guid);
    }
    /// <summary>
    /// Copy constructor.
    /// </summary>
    public PrimaryValue(PrimaryValue pValue)
    {
        _value = pValue._value;
        _type = pValue._type;
    }
    public void set(PrimaryValue pValue)
    {
        if (_type == pValue._type)
        {
            _value = pValue._value;
            return;
        }
        throw new ModelException("PrimaryValues are not of the same type.");
    }
    /// <summary>
    /// Assigns a UINT value.
    /// </summary>
    public void set(uint pValue)
    {
        if (_type == typeof(uint))
        {
            _value = pValue;
            return;
        }
        throw new ModelException("PrimaryValue is not a UINT type.");
    }
    /// <summary>
    /// Assigns a GUID value.
    /// </summary>
    public void set(Guid pValue)
    {
        if (_type == typeof(Guid))
        {
            _value = pValue;
            return;
        }
        throw new ModelException("PrimaryValue is not a GUID type.");
    }
    /// <summary>
    /// Returns the raw value.
    /// </summary>
    public object get()
    {
        return _value;
    }
    /// <summary>
    /// Gets the ID as UINT.
    /// </summary>
    public uint ToInteger()
    {
        if (_type != typeof(uint))
        {
            throw new ModelException("PrimaryValue is not a UINT type.");
        }
        return (uint)_value;
    }
    /// <summary>
    /// Gets the ID as GUID.
    /// </summary>
    public Guid ToGuid()
    {
        if (_type != typeof(Guid))
        {
            throw new ModelException("PrimaryValue is not a GUID type.");
        }
        return (Guid)_value;
    }
    /// <summary>
    /// Checks if two IDs are equal.
    /// </summary>
    public static bool operator ==(PrimaryValue A, PrimaryValue B)
    {
        if (A._value.GetType() == B._value.GetType())
        {
            return A._value == B._value;
        }
        throw new ModelException("Can not compare PrimaryValues of different types.");
    }
    /// <summary>
    /// Checks if two IDs are not equal.
    /// </summary>
    public static bool operator !=(PrimaryValue A, PrimaryValue B)
    {
        if (A._value.GetType() == B._value.GetType())
        {
            return A._value != B._value;
        }
        throw new ModelException("Can not compare PrimaryValues of different types.");
    }
    /// <summary>
    /// Convertion to UINT.
    /// </summary>
    public static implicit operator uint(PrimaryValue A)
    {
        return A.ToInteger();
    }
    /// <summary>
    /// Convertion to Guid.
    /// </summary>
    public static implicit operator Guid(PrimaryValue A)
    {
        return A.ToGuid();
    }
    /// <summary>
    /// Convertion to string.
    /// </summary>
    public static implicit operator string(PrimaryValue A)
    {
        return A._value.ToString();
    }
    /// <summary>
    /// Convert to string.
    /// </summary>
    public override string ToString()
    {
        return _value.ToString();
    }
    /// <summary>
    /// Hashcode
    /// </summary>
    public override int GetHashCode()
    {
        return _value.GetHashCode();
    }
}