在C#中不透明的字典键模式 [英] Opaque dictionary key pattern in C#

查看:132
本文介绍了在C#中不透明的字典键模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在若干情况下,其中的一个键控集合访问项目的模式(如字典)是由一个事实,即关键的类型不是简单类型担保(字符串,INT运行,双,等),是不是,你想推广到实际命名的类。

C#3.0中引入了匿名类型,编译器自动生成的概念。不同于结构的,这些动态生成的类提供的两个等于()的实现 GetHash code() - 其目的是为了用字典和哈希表的实现在.NET中工作得很好

我劫持此功能来创建一个不透明的关键 - 基本上是一个泛型类,允许您通过提供的的重要组成部分的类型来创建键上飞 - 和使用匿名类实际提供的Equals / GetHash code行为。这个类的目的是的只有的规定使用几个值一起作为重点成一本字典或哈希表一个简单的方法。它不打算作为一类,以提供有意义的应用程序逻辑或数据操作

该模式的好处是,它可以很容易地实现组合键始终提供适当的平等和散列的行为。这也是很容易地扩展到任意数量的尺寸(但是许多C#至少可以解析为模板参数)键。我们甚至可以通过允许OpaqueKey&LT作出改善;>类从,这样它的属性和构造函数参数可以得到更多的启发性的名字继承

我很担心这种模式可能会有一些意想不到的后果或隐藏的陷阱,我不考虑。

是否有任何理由如下OpaqueKey code可通过不受欢迎?

是否有我的执行有没有考虑过任何优势的情况下?

有没有一种简单的方法来实现相同的功能?

 公共类OpaqueKey< A,B>
{
    私人只读对象m_Key;

    //并非绝对必要,但可能方便...
    公开发行A首先{获得;私定; }
    公众B二{获得;私定; }

    公共OpaqueKey(A K1,B K2)
    {
        m_Key =新{K1 = K1,K2 = K2};
        首先= K1;
        二= K2;
    }

    公众覆盖布尔等于(obj对象)
    {
        VAR otherKey = OBJ为OpaqueKey< A,B取代;
        返回otherKey == NULL?假:m_Key.Equals(otherKey.m_Key);
    }

    公众覆盖INT GetHash code()
    {
        返回m_Key.GetHash code();
    }
}


公共静态无效TrivialTestCase()
{
    VAR字典=新字典< OpaqueKey<字符串,字符串>中字符串>();

    dict.Add(新OpaqueKey<字符串,字符串>(A,B),AB);
    dict.Add(新OpaqueKey<字符串,字符串>(A,C),AC);
    dict.Add(新OpaqueKey<字符串,字符串>(A,D),AD);
    dict.Add(新OpaqueKey<字符串,字符串>(A,E),AE);

    VAR值=词典[新OpaqueKey<字符串,字符串>(A,D);

    Debug.Assert的(价值==AD); //平凡的测试用例...
}
 

解决方案

从我可以告诉,你可以使用一个通用的元组类,你有没有必要的内部匿名类的。一个元组类可能是解决方案中的其他地方有用的(这就是为什么.NET 4.0将内置有通用的元组类)。等于可以比较第一和第二的值,而GetHash code将结合多元组成员的哈希值codeS。

  //4.0 Beta1的GetHash code实现
        INT A = 5; INT B = 10;
        元组LT; INT,INT> T =新行< INT,INT>(A,B);

        Console.WriteLine(t.GetHash code()==(((A&其中;小于5)+α)^ B));
 

I've run across a number of cases where a pattern for accessing items in a keyed collection (like a dictionary) is encumbered by the fact that the type of the key is not a simple type (string, int, double, etc) and isn't something that you would want to promote to an actual named class.

C# 3.0 introduces the concept of anonymous types which the compiler automatically generates. Unlike struct's, these dynamically generated classes provide an implementation of both Equals() and GetHashCode() - which are designed to work well with dictionary and hashtable implementation in .NET.

I've hijacked this feature to create an opaque key - essentially a generic class that allows you to create keys on the fly by providing the types that are part of the key - and using an anonymous class to actually provide the Equals/GetHashCode behavior. The intent of this class is to ONLY provide a easy means to use several values together as a key into a dictionary or hashtable. It's not intended as a class to provide meaningful application logic or data manipulation.

The benefit of the pattern is that it makes it easy to implement composite keys that always provide appropriate equality and hashing behavior. It's also easily extensible to keys of any number of dimensions (however many C# can parse as template parameters at least). We can even make improvements by allowing the OpaqueKey<> class to be inherited from so that it's properties and constructor parameters can be given more instructive names.

I am worried that this pattern may have some unintended consequences or hidden pitfalls that I'm not considering.

Are there any reasons why the following OpaqueKey code may by undesirable?

Are there any edge cases that I haven't considered in the implementation?

Is there a simpler way to achieve the same functionality?

public class OpaqueKey<A,B>
{
    private readonly object m_Key;

    // Not strictly necessary, but possibly convenient...
    public A First { get; private set; }
    public B Second { get; private set; }

    public OpaqueKey( A k1, B k2 )
    {
        m_Key = new { K1 = k1, K2 = k2 };
        First = k1;
        Second = k2;
    }

    public override bool Equals(object obj)
    {
        var otherKey = obj as OpaqueKey<A, B>;
        return otherKey == null ? false : m_Key.Equals( otherKey.m_Key );
    }

    public override int GetHashCode()
    {
        return m_Key.GetHashCode();
    }
}


public static void TrivialTestCase()
{
    var dict = new Dictionary<OpaqueKey<string,string>, string>();

    dict.Add(new OpaqueKey<string, string>("A", "B"), "AB");
    dict.Add(new OpaqueKey<string, string>("A", "C"), "AC");
    dict.Add(new OpaqueKey<string, string>("A", "D"), "AD");
    dict.Add(new OpaqueKey<string, string>("A", "E"), "AE");

    var value = dict[new OpaqueKey<string,string>("A","D")];

    Debug.Assert( value == "AD" ); // trivial test case...
}

解决方案

From what I can tell, you can use a generic Tuple class, and you have no need of the inner anonymous class. A Tuple class could be useful elsewhere in your solution (which is why .NET 4.0 will have built-in generic Tuple classes). Equals can compare the values of First and Second, while GetHashCode would combine the hashcodes of the Tuple's members.

        //4.0 Beta1 GetHashCode implementation
        int a = 5; int b = 10;
        Tuple<int, int> t = new Tuple<int, int>(a, b);

        Console.WriteLine(t.GetHashCode() == (((a << 5) + a) ^ b));

这篇关于在C#中不透明的字典键模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆