14

我有一个名为 EntityTypeTransform 的抽象类,它有一个抽象方法,旨在保存一个将 IDataRecord 转换为 T 实例的 Func 委托。

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<Type, EntityTypeTransform<T>>

但这不起作用,因为(例如)TaskParameter 的EntityTypeTransform 的实例与TaskParameter 的EntityTypeTransform 的实例不同。

谁能帮我吗?

编辑:我应该添加 Type key = typeof(T)

4

7 回答 7

9

实际上,您根本不需要使用字典!您可以使用GenericClass<T>每个 T 实际上是不同类型的事实,因此它可以有自己的静态字段(即GenericClass<Foo>.SomeField不与 共享GenericClass<Bar>.SomeField

例如,您可以像这样实现缓存:

static class TransformCache<TEntityType>
{
    public static EntityTypeTransform<TEntityType> Transform { get; set; }
}

并像这样使用它:

TransformCache<TaskParameter>.Transform = new TaskParameterEntityTypeTransform();
于 2013-10-23T22:29:54.910 回答
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 回答
1

您可以使用KeyedByTypeCollection来获得类型安全,并且可以使用协变类型参数定义接口,以确保只能将类型的对象EntityTypeTransform<T>添加到字典中:

public interface IEntityTypeTransform<out TEntityType> where TEntityType : class
{
    TEntityType Transform(IDataRecord dataRecord);
}

public abstract class EntityTypeTransform<TEntityType> : IEntityTypeTransform<TEntityType> where TEntityType : class
{
    public abstract TEntityType Transform(IDataRecord dataRecord);
}

public class TaskParameter
{
    public int TaskId;
    public string Name;
    public string Value;
}

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

public class SomeClass
{
    public KeyedByTypeCollection<IEntityTypeTransform<object>> TransformDictionary = new KeyedByTypeCollection<IEntityTypeTransform<object>>()
    {
        new TaskParameterEntityTypeTransform(),
        // More transforms here
    };
}

现在你可以像这样使用它:

public void SomeMethod(IDataRecord dataRecord)
{
    TaskParameter taskParameter = TransformDictionary.Find<TaskParameterEntityTypeTransform>().Transform(dataRecord);
}
于 2013-10-23T14:42:22.420 回答
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 回答
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 回答