Коллекция пар ключ-значение, где известен только тип ключа

Мне нужен класс коллекции пар ключ-значение, где я не знаю тип ключа на уровне создания экземпляра, но плохо знаю тип значения только при добавлении нового элемента в коллекцию.

Рассмотрим фрагмент кода ниже

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

Это работает хорошо, однако проблема с приведенным выше кодом заключается в том, что тип вставки должен быть типа IValue, поскольку примитивы не реализуют IValue, и их нельзя добавить в список.

Я не могу использовать object вместо TValue / IValue

ИЗМЕНИТЬ

Я хотел бы использовать любой! тип для параметра значения пары ключ-значение. Если возможно, я хотел бы избавиться от IValue. Это был единственный способ заставить код компилироваться.

Пример идеального использования выглядит следующим образом:

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

EDIT Я не могу использовать объект, так как объект не все объекты сериализуемы, однако я изменил реализацию на

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

Компилятор говорит argument type <TKey, TValue> is not assignable to parameter type <TKey, ISerializable>


person Aiden Strydom    schedule 05.06.2015    source источник
comment
У вас противоречивые требования. Вы говорите о примитивах (типах значений?), которые хотите добавить в коллекцию, которая допускает только типы, реализующие IValue.   -  person CodeCaster    schedule 05.06.2015
comment
Можете ли вы объяснить, почему вы не можете использовать объект?   -  person Zotta    schedule 05.06.2015
comment
Почему вы не можете расширить примитивы с помощью IValue и использовать расширенный класс?   -  person Jegan    schedule 05.06.2015
comment
@CodeCaster, ты неправильно понял. Я только добавил Ivalue, чтобы получить код для компиляции. Классу keyValue требуется два типа, однако класс Collection определяет только один универсальный тип. Если бы я мог избавиться от IValue, было бы здорово   -  person Aiden Strydom    schedule 05.06.2015
comment
@Jegan - я мог бы написать класс-оболочку ... но я чувствую, что это скорее взлом   -  person Aiden Strydom    schedule 05.06.2015
comment
Ваша коллекция отличается от Dictionary<TKey, object>?   -  person dureuill    schedule 05.06.2015
comment
объект сериализуем, так же как и сборка в «System.Collections.Generic.KeyValuePair»»   -  person BjarkeCK    schedule 05.06.2015


Ответы (2)


Примечание заранее: в качестве личного предпочтения я предпочитаю использовать словарь для пар ключ/значение с уникальными ключами или multimap/ilookup, когда мне нужны дублирующие вводы ключей.


Если вы используете С# 3.5 или старше, вы можете использовать

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

Предполагая, что вы работаете на С# 4, вы можете использовать

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

Людям нравится использовать его, например, для хранения данных JSON.


С Rx-Linq можно делать много чего, но вместо этого я хотел бы отметить, что вы можете написать:

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

где вы можете хранить скрипт, который генерирует строку.

person Margus    schedule 05.06.2015

Если вы хотите, чтобы ваши значения содержали примитивные типы, такие как int, float и т. д., и пользовательские типы, вам следует использовать объект вместо 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));
    }
}

Кроме того, вы можете изменить ICollection<...> на просто Dictionary<TKey, object>, если вам нужен быстрый поиск ключа на основе хэша во время выполнения.

person BjarkeCK    schedule 05.06.2015
comment
Как примечание: это будет активно использовать бокс и может быть проблемой производительности. - person ; 05.06.2015
comment
Это очевидный ответ, но OP сказал Я не могу использовать объект вместо Value/IValue. Если не ясно, почему нет, я бы воздержался от ответа на очевидное. - person CodeCaster; 05.06.2015