【问题标题】:Get the reference of a collection given a type获取给定类型的集合的引用
【发布时间】:2015-11-11 17:42:57
【问题描述】:

我有几本词典:

Dictionary<int, Type1> Type1Dictionary { get; set; }
Dictionary<int, Type2> Type2Dictionary { get; set; }
Dictionary<int, Type3> Type3Dictionary { get; set; }
Dictionary<int, Type4> Type4Dictionary { get; set; }

Typei (i = 1..4) 派生自同一个基类 (BaseType)。我想要一个返回给定类型的字典引用的方法。稍后,我将对该字典执行一些操作,例如添加或删除:

Type1 example = new Type1(); 
var dic = GetDictionary(example);
dic.Add(example.ID, example);

注意:我不想将我的字典设置为Dictionary&lt;int, BaseType&gt;

我可以写这样的东西,但不会返回对字典的引用:

Dictionary<int, BaseType> GetDictionary(BaseType myObject)
{
    var dic = new Dictionary<int, BaseType>();
    if(myObject is Type1)
    {
    //ideally I would return my Type1Dictionary here but I can't due type incompatibility
       foreach(var x in Type1Dictionary)
       {
            dic.Add(x.Key, x.Value);
       }
       return dic;
    }
    if(myObject is Type2) { /*...*/ }
    if(myObject is Type3) { /*...*/ }
    if(myObject is Type4) { /*...*/ }
}

编辑:

我真正想要的是避免以下结构:

AddObject(BaseType x)
{
    Type1 x1 = x as Type1;
    if(x1 != null) { Type1Dictionary.Add(x1.ID, x1); }

    Type2 x2 = x as Type2;
    if(x2 != null) { Type2Dictionary.Add(x2.ID, x2); }

    Type3 x3 = x as Type3;
    if(x3 != null) { Type3Dictionary.Add(x3.ID, x3); }

    Type4 x4 = x as Type4;
    if(x4 != null) { Type4Dictionary.Add(x4.ID, x4); }
}

RemoveObject(BaseType x)
{
    Type1 x1 = x as Type1;
    if(x1 != null) { Type1Dictionary.Remove(x1.ID); }

    Type2 x2 = x as Type2;
    if(x2 != null) { Type2Dictionary.Remove(x2.ID); }

    Type3 x3 = x as Type3;
    if(x3 != null) { Type3Dictionary.Remove(x3.ID); }

    Type4 x4 = x as Type4;
    if(x4 != null) { Type4Dictionary.Remove(x4.ID); }
}

但是:

AddObject(BaseType x)
{
    var dic = GetDictionary(x);
    dic.Add(x.ID, x);
}

RemoveObject(BaseType x)
{
    var dic = GetDictionary(x);
    dic.Remove(x.ID);
}

【问题讨论】:

  • 您不想要一本从 int 映射到 BaseType 的字典,但您返回的字典做同样的事情?
  • 我不想让Type2 对象与Type1 在同一个字典中。但是为了删除或添加一个对象,我真的不在乎字典是如何处理的(如果它是正确的类型)。我写的代码并没有解决我的问题,顺便说一句。
  • 听起来像是访问者模式的候选者,或者使用 dynamic 并将问题移至 DLR。

标签: c#


【解决方案1】:

这可以在广告安全等方面进行完善。但是您应该能够得到基本的想法:

public interface IEntity
{
  int ID { get; }
}

public class Superset<T> where T : IEntity
{
  public Dictionary<Type, Dictionary<int, T>> m_Map = 
    new Dictionary<Type, Dictionary<int, T>>();

  private Dictionary<int, T> GetDictionary(Type t)
  {
    Dictionary<int, T> result = null;
    if (!m_Map.TryGetValue(t, out result))
    {
      result = new Dictionary<int, T>();
      m_Map.Add(t, result);
    }
    return result;
  }

  public void Add<K>(K item) where K : T
  {
    GetDictionary(typeof(K)).Add(item.ID, item);
  }

  public bool Remove<K>(K item) where K : T
  {
    return GetDictionary(typeof(K)).Remove(item.ID);
  }
}

【讨论】:

  • 值得补充的是,这个解决方案仍然只创建一个基本类型的字典,每个typeof(K) 只创建一个字典,尽管这在问题中并未说明为问题。
【解决方案2】:

DLR 可以玩这些技巧:动态调度。它在运行时解析所需的方法。这允许您拥有许多强类型的字典,但具有更通用的处理机制。我这样做是为了处理来自公共事件库的事件。

class Program
{
    private static Dictionary<int, Foo> _foos = new Dictionary<int, Foo>();
    private static Dictionary<int, Baz> _bazs = new Dictionary<int, Baz>();

    static void Main(string[] args)
    {
        Bar foo = new Foo();
        Bar baz = new Baz();

        Add(foo); // Resolves at runtime to Add(Foo f)
        Add(baz); // Resolves at runtime to Add(Baz b)
    }

    public static void Add(Bar b)
    {
        Add((dynamic)b);
    }

    private static void Add(Foo f)
    {
        _foos.Add(1, f);
    }

    private static void Add(Baz b)
    {
        _bazs.Add(1, b);
    }
}

class Foo : Bar
{   
}

class Baz : Bar
{
}

class Bar
{
}

将内容移入 DLR 有其自身的缺陷(即编译时问题现在变成运行时问题),因此需要审查。这只是一种方法。另一种方法是访问者模式的实现。另一种方法是您目前所拥有的。

不要把这个答案当作的方法。

【讨论】:

    猜你喜欢
    • 2013-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-09
    • 2012-06-08
    • 2020-05-25
    • 2010-11-06
    • 1970-01-01
    相关资源
    最近更新 更多