1

I've a Dictionary:

private Dictionary<MetaInfoValueGroupTag, List<object>> checkedMetainfoValues;

As you can see the Key class is MetaInfoValueGroupTag:

private class MetaInfoValueGroupTag
{
    private string metainfo;
    //...

    public string MetaInfo
    {
        get { return metainfo; }
        set { metainfo = value; }
    }
    //...
}

I need to obtain the Value using a string object. So, I need to check whether a key exists according a string.

This string value represents a Metainfo property string content of MetaInfoValueGroupTag dictionary key object.

List<object> values = null;
this.checkedMetainfoValues.TryGetValue("metainfo_sample", out values);

I don't want to write it:

List<object> values = null;
this.checkedMetainfoValues.TryGetValue(new MetaInfoValueGroupTag("metainfo_sample"), 
                                       out values);

I want to avoid to have to create a new dump key object in order to obtain its values.

I figure out it must be possible implementing an IComparer or using an AnonymousComparer.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
Jordi
  • 20,868
  • 39
  • 149
  • 333
  • 1
    "in order to obtain its values" - if values semantically belong to strings, rather than to `MetaInfoValueGroupTag`s, why not key the dictionary by `string` ? – AakashM Sep 04 '15 at 07:27
  • I need to relate some extra information to each group of values. – Jordi Sep 04 '15 at 07:28
  • Can't you use Tuple> as value then? So you will use Dictionary>>. – piotrwest Sep 04 '15 at 07:30
  • I think what it cares... Is it not possible to solve my approach? – Jordi Sep 04 '15 at 07:34
  • It's better not to use key for holding info. Use a Tuple as @piotrwest suggseted or make an additional class that wraps your `MetaInfoValueGroupTags` and `List`. – CodingFeles Sep 04 '15 at 07:57
  • Is there an actual reason why you'd use `MetaInfoValueGroupTags` as the key, and not its `MetaInfo` string representation, given the fact that it's unique? Do you actually use any other property inside your class for equality? – Yuval Itzchakov Sep 04 '15 at 08:15
  • @Jordi if you have some additional info within your keys apart `MetaInfo` than `new MetaInfoValueGroupTag("metainfo_sample")` won't work unless it's `GetHashCode` explicitly use only `MetaInfo`. – CodingFeles Sep 04 '15 at 08:15

4 Answers4

0

Dictionary doesn't work that way.It builds hashtable for keys of its elements and use it for quick search.

It uses IEqualityComparer<T> for determenation that keys are equal, but you can't use it to compare it with diffent type other than your MetaInfoValueGroupTag.

However, you can use LINQ extensions method and use the fact that Dictionary is IEnumerable. That means that you can enumerate it element by element and find what you need. Here, you can use custom comparer or just lambda predicate.

In order to use extensions method you need to add using for them:

using System.Linq;

After that you can use following method with your dictionary in order to find single element:

var searchedElement = checkedMetainfoValues.SingleOrDefault(x=>x.Key.MetaInfo == "metainfo_sample");

But keep in mind that it would kill any dictionary benefits of quick getting of the element. It would simply check all elements one by one untill provided condition fulfils or end of the dictionary is reached.

In the end it's better to modify your dictionary to use string as a key or, if it's not possible, just create MetaInfoValueGroupTag object and use it as a key.

But be aware, that it depends on the hashing algorithm for MetaInfoValueGroupTag. It can be possible that hash value will depend not only on MetaInfo value and so new MetaInfoValueGroupTag("metainfo_sample") may not be suitable for your search.

Read more: https://msdn.microsoft.com/en-us/library/xfhwa508(v=VS.110).aspx

CodingFeles
  • 374
  • 5
  • 18
0

You could obtain the whole key/value pair like this:

var entry = checkedMetainfoValues.Where(x => x1.Key.MetaInfo == "metainfo_sample").Single();
Bgl86
  • 727
  • 8
  • 20
0

I guess the string value is unique, otherwise your access by string wouldn't work. I propose to change the key to string.

private Dictionary<string, List<object>> checkedMetainfoValues;

// access by meta info:
MetaInfoValueGroupTag metaInfoGroupTag;
var value = checkedMetaInfoValues[metaInfoGroupTag.MetaInfo]

// access by string:
string metaInfo;
var value = checkedMetaInfoValues[metaInfo]
Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
0

If you want specifically that syntax:

List<object> values = null;
this.checkedMetainfoValues.TryGetValue("metainfo_sample", out values);

You can create your own dictionary, which inherits from normal dictionary, as follows:

private class MyStrangeDictionary : Dictionary<MetaInfoValueGroupTag, List<object>>
{
    public MyStrangeDictionary() : base(MetaInfoValueGroupTag.MetainfoComparer)
    {
    }

    public List<object> this[string key]
    {
        get
        {
            return this[new MetaInfoValueGroupTag {MetaInfo = key}];
        }
        //set
        //{
        //    Add(new MetaInfoValueGroupTag { MetaInfo = key }, value);
        //} 
    }

    public bool TryGetValue(string key, out List<object> value)
    {
        if (ContainsKey(new MetaInfoValueGroupTag {MetaInfo = key}))
        {
            value = this[key];
            return true;
        }
        value = default(List<object>);
        return false;
    }
}

The usage will be as follows:

_checkedMetainfoValues = new MyStrangeDictionary();

_checkedMetainfoValues.Add(new MetaInfoValueGroupTag { MetaInfo = "f"}, new List<object> { "first"});
_checkedMetainfoValues.Add(new MetaInfoValueGroupTag { MetaInfo = "s"}, new List<object> { "second", "2"});

var test = _checkedMetainfoValues["f"];
foreach (var t in test)
{
    Console.WriteLine(t);
}

List<object> test1;
_checkedMetainfoValues.TryGetValue("s", out test1);
foreach (var t in test1)
{
    Console.WriteLine(t);
}

EDIT:

For the sake of completeness here is your class along with comparer:

private class MetaInfoValueGroupTag
{
    private sealed class MetainfoEqualityComparer : IEqualityComparer<MetaInfoValueGroupTag>
    {
        public bool Equals(MetaInfoValueGroupTag x, MetaInfoValueGroupTag y)
        {
            if (ReferenceEquals(x, y)) return true;
            if (ReferenceEquals(x, null)) return false;
            if (ReferenceEquals(y, null)) return false;
            if (x.GetType() != y.GetType()) return false;
            return string.Equals(x.metainfo, y.metainfo);
        }

        public int GetHashCode(MetaInfoValueGroupTag obj)
        {
            return (obj.metainfo != null ? obj.metainfo.GetHashCode() : 0);
        }
    }

    private static readonly IEqualityComparer<MetaInfoValueGroupTag> MetainfoComparerInstance = new MetainfoEqualityComparer();

    public static IEqualityComparer<MetaInfoValueGroupTag> MetainfoComparer
    {
        get { return MetainfoComparerInstance; }
    }

    private string metainfo;
    //...

    public string MetaInfo
    {
        get { return metainfo; }
        set { metainfo = value; }
    }
    //...
}
piotrwest
  • 2,098
  • 23
  • 35
  • You suggest him to make a wrapper that will do the thing that he try to avoid. It's stated in the question that he wanted to avoid creating object only for using it as a key. – CodingFeles Sep 04 '15 at 08:13
  • We don't know if he wanted to avoid creating object because of syntax reason (maybe he want's to expose that API in library) or because of performance reasons. In the first case, this approach is okey-ish, IMHO. – piotrwest Sep 04 '15 at 08:14
  • I think "**dump** key object" implies that. But, of course, I could misunderstood that. Still defining one type as a key and actually using another is bad. – CodingFeles Sep 04 '15 at 08:20