【问题标题】:Get value from Dictionary<string, object> without unboxing?从 Dictionary<string, object> 获取价值而不拆箱?
【发布时间】:2023-03-17 13:38:01
【问题描述】:

我想知道是否可以运行以下代码但没有拆箱行:-

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

提前致谢!!

理查德。

【问题讨论】:

  • 不,如果您的 object 是盒装值类型,则需要将其拆箱。您是否有理由避免拆箱?
  • 主要是为了性能,因为我的项目中此代码与其他东西一起使用,拆箱将执行时间从 ~200ms 增加到 ~1700ms。这仍然可以接受,我只是想知道是否有替代方案。
  • 这种急剧的性能下降极不可能是由于拆箱造成的。使用分析器确定真正的瓶颈是什么。

标签: c# generics casting boxing


【解决方案1】:

几个cmets:

  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&lt;T&gt; 的实例,它表示字典中没有键为key 的对象。我认为这与大多数人的期望非常违反直觉。

另外,如果你不想在dictionary 不包含匹配键key 的值时抛出,我认为你应该将你的方法重命名为TryGetValue,接受out 类型的参数ValueWrapper&lt;T&gt;,并返回一个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);

您必须添加参数检查等。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-26
    • 1970-01-01
    • 2021-07-18
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多