14

IDataRecord を T のインスタンスに変換する Func デリゲートを保持するように設計された単一の抽象メソッドを持つ EntityTypeTransform という抽象クラスがあります。

public abstract class EntityTypeTransform<TEntityType> where TEntityType : class
{
    public abstract Func<IDataRecord, TEntityType> GetDataTransform();
}

そのクラスの実装は次のようになります (実際にはそうです):

public class TaskParameterEntityTypeTransform : EntityTypeTransform<TaskParameter>
{
    public override Func<IDataRecord, TaskParameter> GetDataTransform()
    {
        return dataRecord => new TaskParameter()
        {
            TaskId = (int)dataRecord["task_id"],
            Name = (string)dataRecord["p_name"],
            Value = (string)dataRecord["p_value"]
        };
    }
}

ここで、これらの各クラスのインスタンスを、次のような一般的な Dictionary に保持したいと考えています。

Dictionary<Type, EntityTypeTransform<T>>

しかし、(たとえば) EntityTypeTransform Of Task のインスタンスは EntityTypeTransform Of TaskParameter のインスタンスと同じではないため、これは機能しません。

誰でも私を助けることができますか?

編集: Type キー = typeof(T) を追加する必要があります

4

7 に答える 7

5

異なるジェネリック型を保持する強い型指定のコレクションを指定することはできません。同様の問題で使用したアプローチを、要件に合わせて変更したものを次に示します。

class TransformCollection
{
   private Hashtable cache = new Hashtable();

   public void Add<T>(EntityTypeTransform<T> transform) where T : class
   {
      this.cache[typeof(T)] = itemToCache;
   }

   public bool Exists<T>() where T : class
   {
      return this.cache.ContainsKey(typeof(T));
   }

   public EntityTypeTransform<T> Get<T>() where T : class
   {
      if (!this.Exists<T>())
         throw new ArgumentException("No cached transform of type: " + typeof(T).Name);
      return this.cache[typeof(T)] as EntityTypeTransform<T>;
   }
}

これにより、ジェネリック型のタイプ セーフ キャッシュが提供されます (ただし、タイプ セーフは C# ではなく、クラスのロジックによって適用されます)。次のように使用できます。

var collection = new TransformCollection();
collection.Add(SomeMethodToGetTransform<Task>());
//...
if (collection.Exists<Task>())
{
   var transform = collection.Get<Task>();
   //...
}
于 2013-10-23T14:24:57.703 に答える
3

非ジェネリックなインターフェイスを使用して、そのインターフェイスをその抽象クラス内に明示的に実装できます。.Net ライブラリ自体ではかなり一般的です。

public interface IEntityTypeTransform
{
    Func<IDataRecord, object> GetDataTransform();
}

public abstract class EntityTypeTransform<TEntityType> : IEntityTypeTransform
    where TEntityType : class
{
    public virtual Func<IDataRecord, TEntityType> GetDataTransform()
    {
        return this.GetDataTransformImpl();
    }

    public abstract Func<IDataRecord, TEntityType> GetDataTransformImpl();

    Func<IDataRecord, object> IEntityTypeTransform.GetDataTransform()
    {
        return this.GetDataTransform();
    }
}
于 2013-10-23T14:22:44.863 に答える
2

たとえば、非ジェネリックな基本クラスを作成する必要があります。

public abstract class EntityTypeTransformBase
{
    public abstract Func<IDataRecord, object> GetDataTransform();
}

public abstract class EntityTypeTransform<TEntityType> : EntityTypeTransformBase where TEntityType : class
{
    public abstract Func<IDataRecord, TEntityType> GetDataTransformImpl();

    public override Func<IDataRecord, object> GetDataTransform()
    {
        return GetDataTransformImpl();
    }
}

public class TaskParameterEntityTypeTransform : EntityTypeTransform<TaskParameter>
{
    public override Func<IDataRecord, TaskParameter> GetDataTransformImpl()
    {
        return dataRecord => new TaskParameter()
        {
            TaskId = (int)dataRecord["task_id"],
            Name = (string)dataRecord["p_name"],
            Value = (string)dataRecord["p_value"]
        };
    }
}

これで、辞書を作成できます。

var d = new Dictionary<Type, EntityTypeTransformBase>();
d.Add(typeof(TaskParameter), new TaskParameterEntityTypeTransform());
于 2013-10-23T14:22:42.383 に答える
0

非ジェネリック インターフェイスをトランスフォーマーに追加します。

public interface IEntityTypeTransform
{
    Func<IDataRecord, object> GetDataTransform();
}
public abstract class EntityTypeTransform<T> : IEntityTypeTransform
{
    public abstract Func<IDataRecord, object> GetDataTransform();
}
public class TaskParameterEntityTypeTransform : EntityTypeTransform<TaskParameter>
{
    public override Func<IDataRecord, object> GetDataTransform()
    {
        return dataRecord => new TaskParameter()
        {
            TaskId = (int)dataRecord["task id"],
        };
    }
}

次に、データ型が常に一致するように辞書をカプセル化できます。不正なタイプの IEntityTypeTransform の追加を許可しない:

public class TransformDistributor
{
    private readonly Dictionary<Type, IEntityTypeTransform> _transforms = new Dictionary<Type, IEntityTypeTransform>();
    public void Add<T>(EntityTypeTransform<T> type)
    {
        this._transforms.Add(typeof(T), type);
    }
    public T Transform<T>(IDataRecord record)
    {
        var transform = this._transforms[typeof(T)].GetDataTransform()(record);
        if (transform is T)
        {
            return (T)transform;
        }
        else
        {
            // theorically can't happen
            throw new InvalidOperationException("transformer doesn't return instance of type " + transform.GetType().Name);
        }
    }
}

利点は、コンパイル時に、ジェネリックを使用していない場合でも、誰も悪いトランスフォーマーを挿入できないと確信していることです。

使用法 :

var transforms = new TransformDistributor();
transforms.Add<TaskParameter>(new TaskParameterEntityTypeTransform());

var taskParameter = transforms.Transform<TaskParameter>(new DataRecord());
于 2013-10-23T14:33:59.183 に答える
0

私はあなたが正確に何を望んでいるのかを理解しようとしました。これがまさにあなたが探しているものであることを願っています!

TaskParameter クラスに正しいパラメータを設定する必要があります: TaskId、Name、Value

public abstract class EntityTypeTransform<TEntityType> where TEntityType : class
{
  public abstract Func<IDataRecord, TEntityType> GetDataTransform();
}

public class TaskParameterEntityTypeTransform : EntityTypeTransform<TaskParameter>
{
  public override Func<IDataRecord, TaskParameter> GetDataTransform()
  {
    return x => new TaskParameter { X = x.FieldCount };
  }
}

public class TaskParameter
{
  public int X { get; set; }
}

Dictionary<Type, EntityTypeTransform<TaskParameter>> imADict;
于 2013-10-23T14:38:35.897 に答える