Получить значение из словарябез распаковки? - PullRequest
4 голосов
/ 21 октября 2010

Мне было интересно, можно ли запустить следующий код, но без строки распаковки: -

t.Value = (T)x;

Или, может быть, есть ли другой способ выполнить такую ​​операцию?

Вот полный код: -

public class ValueWrapper<T>
{
    public T Value { get; set; }
    public bool HasValue { get; set; }

    public ValueWrapper()
    {
        HasValue = false;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Dictionary<string, object> myDictionary = new Dictionary<string, object>();

        myDictionary.Add("key1", 6);
        myDictionary.Add("key2", "a string");

        var x2 = GetValue<int>(myDictionary, "key1");
        if (x2.HasValue)
            Console.WriteLine("'{0}' = {1}", "key1", x2.Value);
        else
            Console.WriteLine("No value found");

        Console.ReadLine();
    }

    static ValueWrapper<T> GetValue<T>(IDictionary<string, object> dictionary, string key)
    {
        ValueWrapper<T> t = new ValueWrapper<T>();

        object x = null;
        if (dictionary.TryGetValue(key, out x))
        {
            if (x.GetType() == typeof(T))
            {
                t.Value = (T)x;
                t.HasValue = true;
            }
        }

        return t;
    }
}

Заранее спасибо !!

Ричард.

1 Ответ

6 голосов
/ 21 октября 2010

Несколько комментариев:

  1. t.Value = (T)x;

Приведение необходимо.Это потому, что t.Value имеет тип T, а x имеет тип object.Строго типизированная природа C # требует, чтобы вы сказали компилятору: «Послушайте, я знаю, что это может быть небезопасно, но можете ли вы просто попытаться сделать это для меня в любом случае, путем преобразования или распаковки или чего-то еще? Спасибо!»

2.

object x = null;
if (dictionary.TryGetValue(key, out x)) {
    if (x.GetType() == typeof(T)) {
        t.Value = (T)x;
        t.HasValue = true;
    }
}

return t;

Что если x является экземпляром класса, производного от T?Или, если x является экземпляром класса, который реализует интерфейс, и T это интерфейс?Прямо сейчас вы вернете экземпляр ValueWrapper<T>, который указывает, что в словаре не было объекта с ключом key.Я бы сказал, что это очень противоречит тому, что ожидает большинство людей.

Кроме того, если вы не собираетесь вырвать, когда dictionary не содержит значение, соответствующее ключу key, я думаю, вам следуетпереименуйте ваш метод в TryGetValue, примите параметр out типа ValueWrapper<T> и верните bool, указывающий на успех / неудачу.

3.

Отвечая на ваш комментарий,вот одно решение.

public interface IValueWrapper {
    object Value { get; set; }
    bool HasValue { get; set; }
}

public class ValueWrapper<T> : IValueWrapper {
    public T Value { get; set; }
    object IValueWrapper.Value { 
        get { return Value; }
        set { this.Value = (T)value; }
    }
    public bool HasValue { get; set; }

    public ValueWrapper() {
        this.HasValue = false;
    }

    public ValueWrapper(T value) {
        this.Value = value;
        this.HasValue = value != null;
    }
}

public static class DictionaryExtensions {
    public static void Add<T>(
        this IDictionary<string, IValueWrapper> dictionary,
        string key,
        T value
    ) {
        ValueWrapper<T> valueWrapper = new ValueWrapper<T>(value);
        dictionary.Add(key, valueWrapper);
    }

    public static bool TryGetWrappedValue<T>(
        IDictionary<string, IValueWrapper> dictionary,
        string key,
        out ValueWrapper<T> value
    ) {
        IValueWrapper valueWrapper;
        if (dictionary.TryGetValue(key, out valueWrapper)) {
            value = (ValueWrapper<T>)valueWrapper;
            return true;
        }
        else {
            value = null;
            return false;
        }
    }
}

Использование:

var dict = new Dictionary<string, IValueWrapper>();
dict.Add("hello", 5);
ValueWrapper<int> value;
dict.TryGetWrappedValue("hello", out value);

Вам нужно будет добавить проверку параметров и т. д.

...