0

と呼ばれる多くの機能を含むクラスがありますRecord。システムには、主キーが であるレコードと、主キーが であるレコードの 2 つの基本タイプが存在しuintますGuid

このRecordクラスには、1 つのプロパティを除いて、必要なすべての機能が含まれています。Record.ID開発者は、現在の主キーを正しいタイプ (uintまたはGuid) として読み取ることができます。

これを実現するには、次のような 3 つのクラスを作成する必要がありました (単純化された例)。

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

これは、単純に 2 つのタイプを持つことの利点よりも多くの問題を引き起こしましたRecord。モデルをインスタンス化するとき、コードは必要なタイプを認識しているRecord必要があります。それが一般的なセクションで行われる場合は、別のテンプレート引数を追加する必要があります。

しばらくすると、テンプレート引数を使用するメソッドがたくさんあることに気付きました。型を に渡すことができるようにするためだけにModel<RecordGuid>、実際にそれを必要とするコードに到達する前に、テンプレート引数をいくつかのメソッド呼び出しのチェーンに渡す必要がある場合があります。

私がやっていることよりも効果的なパターンはありますか?

編集:

がテンプレート引数を使用する理由の 1 つModelは、 のコレクションを返すメソッドが必要だからですRecord。C# では にキャストできないため、戻り値の型としてテンプレート引数を使用する必要がList<Record>ありました。List<RecordGuid>List<T>

4

1 に答える 1

2

主キーを表す新しいクラスを作成し、そのクラスTypeでその ID の状態を制御することにしました。

これにより、単一のクラスを作成して、そのクラスが主キーまたは主キーRecordのいずれかをサポートできる時間を表すことができます。また、クラスがテンプレート引数を必要としなくなったことも意味します。その結果、依存する他のソース コードもテンプレート引数を必要としなくなりました。uintGuidModelModel

これが私が使用している私の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();
    }
}
于 2013-05-21T16:50:48.510 に答える