简体   繁体   English

保持字典 <Type, MyClass<T> &gt;哪些元素可按类型引用

[英]Keep a Dictionary<Type, MyClass<T>> where elements are referenceable by type

I have an abstract class called EntityTypeTransform with a single abstract method designed to hold a Func delegate that converts an IDataRecord into an instance of T. 我有一个名为EntityTypeTransform的抽象类,它有一个抽象方法,用于保存将IDataRecord转换为T实例的Func委托。

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

An implementation of that class might look like (does look like) this: 该类的实现可能看起来像(看起来像):

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"]
        };
    }
}

Now I want to keep an instance of each of these classes in a generic Dictionary, something like: 现在我想在通用字典中保留每个类的实例,例如:

Dictionary<Type, EntityTypeTransform<T>>

But this doesn't work because (for example) an instance of EntityTypeTransform Of Task is not the same as an instance of EntityTypeTransform Of TaskParameter. 但这不起作用,因为(例如)EntityTypeTransform Of Task的实例与EntityTypeTransform Of TaskParameter的实例不同。

Can anyone help me out? 谁能帮我吗?

Edit: I should add that the Type key = typeof(T) 编辑:我应该添加Type key = typeof(T)

Actually, you don't need to use a dictionary at all! 实际上,你根本不需要使用字典! You can use the fact that GenericClass<T> is actually a different type for each T, so it can have its own static fields (ie GenericClass<Foo>.SomeField is not shared with GenericClass<Bar>.SomeField ) 您可以使用GenericClass<T>实际上是每个T的不同类型的事实,因此它可以有自己的静态字段(即GenericClass<Foo>.SomeField不与GenericClass<Bar>.SomeField共享)

For instance you can implement your cache like this: 例如,您可以像这样实现缓存:

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

And use it like this: 并像这样使用它:

TransformCache<TaskParameter>.Transform = new TaskParameterEntityTypeTransform();

You can't specify a strong-typed collection that would hold different generic types. 您不能指定包含不同泛型类型的强类型集合。 Here's the approach I've used in a similar problem, modified to match your requirement: 这是我在类似问题中使用的方法,经过修改以符合您的要求:

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

This gives you type-safe cache for your generic type (though type-safety is enforced by the class's logic, not C#). 这为您的泛型类型提供了类型安全的缓存(尽管类的安全性是由类的逻辑强制执行的,而不是C#)。 You can use it as follows: 您可以按如下方式使用它:

var collection = new TransformCollection();
collection.Add(SomeMethodToGetTransform<Task>());
//...
if (collection.Exists<Task>())
{
   var transform = collection.Get<Task>();
   //...
}

You could use an interface that is non-generic and then implement that interface explicitly inside that abstract class, It's pretty common in the .Net library itself: 您可以使用非泛型的接口,然后在该抽象类中显式实现该接口,这在.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();
    }
}

You would have to create a non-generic base class, eg 您必须创建一个非泛型基类,例如

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"]
        };
    }
}

Now you can create your dictionary: 现在您可以创建您的字典:

var d = new Dictionary<Type, EntityTypeTransformBase>();
d.Add(typeof(TaskParameter), new TaskParameterEntityTypeTransform());

You can use KeyedByTypeCollection to get type-safety and you can define an interface with a covariant type parameter to make sure that only objects of type EntityTypeTransform<T> can be added to the dictionary: 您可以使用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
    };
}

Now you can use it like this: 现在您可以像这样使用它:

public void SomeMethod(IDataRecord dataRecord)
{
    TaskParameter taskParameter = TransformDictionary.Find<TaskParameterEntityTypeTransform>().Transform(dataRecord);
}

Add a non generic interface to your transformers: 为变换器添加非通用接口:

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"],
        };
    }
}

Then you can encapsulate your dictionary for ensure that datatypes will always match. 然后,您可以封装字典以确保数据类型始终匹配。 Never allow to add a IEntityTypeTransform of a bad type : 永远不允许添加错误类型的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);
        }
    }
}

The advantage are that at compile time, your are sure that nobody can insert a bad transformer, even if your are not using generics. 优点是在编译时,即使您没有使用泛型,也确保没有人可以插入坏变压器。

Usage : 用法:

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

var taskParameter = transforms.Transform<TaskParameter>(new DataRecord());

I have tried to understand what you exactly want I hope this is exactly what you are looking for! 我试图了解你到底想要什么,我希望这正是你所寻找的!

You shall set in TaskParameter class the correct parameters: TaskId, Name, Value 您应在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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 定义一个类MyClass <T> 或函数MyFunction <T> (T x)其中T只能通过实现IMyInterface的类型 - Define a class MyClass<T> or a function MyFunction<T>(T x) where T can only by a type that implements IMyInterface 自引用实体的可空通用接口类型 - nullable generic interface type for self referenceable entities 创建类型“ MyClass:OtherClass <MyClass> {}”在运行时? - Create type “MyClass : OtherClass<MyClass> { }” at runtime? 不能隐式转换类型 MyClassContainer<T> 到 MyClassContainer<MyClass> - Cannot implicitly convert type MyClassContainer<T> to MyClassContainer<MyClass> T字典类型列表 - List of type T to Dictionary 未找到“MyClass”类型的默认构造函数 - default constructor not found of type'MyClass' “MyClass”的类型初始值设定项引发异常 - The type initializer for 'MyClass' threw an exception 加入字典 <int, string> 和清单 <MyClass> 错误(无法从用法中推断出方法的类型参数) - Join Dictionary<int, string> and List<MyClass> error (type arguments for method cannot be inferred from the usage) 无法将List`1 [MyClass]&#39;强制转换为List`1 [MyClass_Accessor]&#39;类型? - Cannot cast List`1[MyClass]' to type List`1[MyClass_Accessor]'? 我可以从泛型类型 T 继承泛型 class 吗? 喜欢我的班级<t> : T</t> - Can I inherit a generic class from a generic type T? Like MyClass<T> : T
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM