2010-10-20 70 views
3

我在想,如果有可能运行下面的代码,但没有拆箱行: -从字典<字符串,对象>不拆箱获取价值?

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

在此先感谢!

Richard。

+0

不,如果你的'object'被装箱值类型,然后它会需要拆箱。你有什么理由要避免拆箱? – LukeH 2010-10-20 22:30:04

+0

主要是因为我的项目中的代码与其他东西一起使用时的性能,拆箱会将执行时间从〜200ms增加到〜1700ms。这仍然是可以接受的,如果有其他选择,我只是想知道为了我自己的利益。 – 2010-10-20 22:46:54

+0

这种剧烈的性能下降是由于拆箱造成的。使用分析器来确定真正的瓶颈是什么。 – Timwi 2010-10-20 23:35:57

回答

5

几点意见:

  1. t.Value = (T)x;

演员是必要的。这是因为t.Value的类型为Tx的类型为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,接受ValueWrapper<T>类型的out参数,并返回一个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); 

你必须添加参数检查等

+0

谢谢你这么快回复,我看到是否有一种方法可以使它成为对象,而不是字典中的V,但也许是别的什么来防止拆箱,因为它可能很慢。 此外,我已经改变了我的方法来引用ValueWrapper并返回true/false,这对我来说确实感觉好多了,我没有想到这一点。 – 2010-10-20 22:42:36

+0

它应该'out'而不是'ref'。 – Timwi 2010-10-20 23:39:12

+0

@Richard Adnams:我怀疑这是导致性能问题的原因,但你只能知道你是否属于配置文件。不过,请参阅我的编辑方式来解决您正在尝试解决的问题。 – jason 2010-10-21 00:09:23

相关问题