0

I want a collection class of key-value pairs, where ill know the key type at instantiation level but ill only know the value type when adding a new element to the collection.

Consider a the code snippet below

public class Collection<TKey> where TKey : class
{
    public ICollection<KeyValuePair<TKey, IValue>> Col { get; set; }

    public void Add<TValue>(TKey key, TValue value) where TValue : IValue
    {
        Col.Add(new KeyValuePair<TKey, IValue>(key, value));
    }
}

public interface IValue
{
}

This works well, however, the problem with the above code is that the insertion type must be of type IValue, since primitives aren't implementers of IValue they cannot be added to the list.

I cannot use object inplace of TValue / IValue

EDIT

I would like to use any! type for the value parameter of the key-value pair. If possible id like to get rid of IValue. It was the only way i could get the code to compile

An example of ideal usage is as follows:

    collection.Add("hello", 10);
    collection.Add("peter", "temp");
    collection.Add("hello1", new Foo());
    collection.Add("hello2", new Bar());

EDIT I cannot use object since object is not all objects are seriablisable, however, i changed the implementation to

class Program
{
    static void Main(string[] args)
    {
        var collection = new Collection<string>();
        collection.Add("hello", 10);
        collection.Add("peter", "temp");
        collection.Add("hello", new Bar());
    }
}

[Serializable]
public class KeyValuePair<TKey, TValue>
{
    private TKey _key;
    private TValue _value;

    public KeyValuePair(TKey key, TValue value)
    {
        _key = key;
        _value = value;
    }

    public TKey Key
    {
        get { return _key; }
        set { _key = value; }
    }

    public TValue Value
    {
        get { return _value; }
        set { _value = value; }
    }
}

public class Collection<TKey> where TKey : class
{
    public ICollection<KeyValuePair<TKey, ISerializable>> Col { get; set; }

    public void Add<TValue>(TKey key, TValue value) where TValue : ISerializable
    {
        Col.Add(new KeyValuePair<TKey, TValue>(key, value));
    }
}

The compiler says argument type <TKey, TValue> is not assignable to parameter type <TKey, ISerializable>

Aiden Strydom
  • 1,198
  • 2
  • 14
  • 43
  • 3
    You have conflicting requirements. You're talking about "primitives" (value types?) you want to add to a collection that only allows types implementing `IValue`. – CodeCaster Jun 05 '15 at 11:00
  • 3
    Can you explain why you can not use object? – Zotta Jun 05 '15 at 11:01
  • Why can't you extend the primitives with IValue and use the extended class? – Jegan Jun 05 '15 at 11:10
  • @CodeCaster you misunderstand. I only added Ivalue so that i could get the code to compile. The keyValue class required two types, however, the Collection class only defined one generic type. If i could get rid of `IValue` that would be great – Aiden Strydom Jun 05 '15 at 11:11
  • @Jegan - i could write a wrapper class... but that's more of a hack i feel – Aiden Strydom Jun 05 '15 at 11:12
  • Is your collection different from `Dictionary`? – dureuill Jun 05 '15 at 11:13
  • object is serializable, so is the build in ´System.Collections.Generic.KeyValuePair<>´ – BjarkeCK Jun 05 '15 at 11:38

2 Answers2

2

Note beforehand : As a personal preference I tend to use dictionary for key/value pairs with unique keys or multimap/ilookup when i need duplicate key inputs.


If you use C# 3.5 or older you can use

var dic = new Dictionary<string, object>();  

Assuming you're on C# 4 you can use

var dic = new Dictionary<string, dynamic>();  

People like to use it to store JSON data for example.


There is a lot what you can do with Rx-Linq, but instead I would like to note that you can write:

var dic = new Dictionary<string, Lazy<string>>();

where you can store a script that generates the string.

Margus
  • 19,694
  • 14
  • 55
  • 103
1

If you want your values to contain primitive types such as int, float ect and custom types, then you should use object instead of IValue.

public class Collection<TKey> where TKey : class
{
    public ICollection<KeyValuePair<TKey, object>> Col { get; set; }

    public void Add(TKey key, object value)
    {
        Col.Add(new KeyValuePair<TKey, object>(key, value));
    }
}

Also, you might want to change ICollection<...> to simply be a Dictionary<TKey, object> if you want fast hashbased key lookup during runtime.

BjarkeCK
  • 5,694
  • 5
  • 41
  • 59
  • 1
    Just as a side-note: this will heavily use boxing and might be a performance issue. –  Jun 05 '15 at 11:16
  • 2
    That is the obvious answer, but OP said _"I cannot use object inplace of TValue / IValue"_. Unless it's clear why not, I'd refrain from answering the obvious. – CodeCaster Jun 05 '15 at 11:17