2

我有一个通用方法,用于将数据库中的字符串值转换为实际转换值。

public MySpecialValue {
    object val;
    bool valSet = false; 

    T GetValue<T> () { 
         if (!valSet)
         {
                val = (T)Convert.ChangeType(DatabaseValue, typeof(T));
                valSet = true;
         }
         return (T)val;
     }

     public string DatabaseValue { get; set; }
}

问题是在初始化期间我不知道数据库中的数据是什么类型,只有在第一次调用时我才能做出这个决定。

有没有办法以不强制拆箱缓存的值类型的方式构造它?(不改变包含类的签名)

4

5 回答 5

5

您提供的代码有些奇怪。“DoSomethingExpensive”如何知道为任意 T返回一个T ?这对我来说毫无意义。

您通常编写通用记忆器的方式是这样的:

public static Func<T> Memoize(this Func<T> func)
{
    bool executed = false;
    T result = default(T);
    Func<T> memoized = ()=> 
    {
        if (!executed)
        {
            result = func();
            executed = true;
        }
        return result;
    };
    return memoized;
}

现在你可以说:

Func<int> expensive = DoSomethingExpensiveThatGetsAnInt;
Func<int> memoized = expensive.Memoize();

你完成了。不需要拳击。

于 2011-01-19T02:21:51.403 回答
3

如果 T 和结果Convert.ChangeType是引用类型,则不会拆箱。

如果Convert.ChangeType返回一个装箱的值类型并且 T 是一个值类型,那么如果您希望 GetValue 返回 T,那么您无法采取任何措施来避免拆箱。

于 2011-01-19T01:27:41.880 回答
1

我愿意打赌(好吧,我也有拥有源代码的优势......)在大多数情况下,这个代码是根据你在回复中的示例调用的

Get("Site.Twitter.AccountName", "")

或者

Get("Site.Twitter.AccountName", 77)

在这种情况下,您使用的是泛型类型推断。但是还有另一个更简单的东西可以在那里编译......不要使用泛型。我希望这里只有几个场景;所以一些类/方法重载 - 一个 for string,一个 forint等。

string Get(string key, string defaultValue) {...}
int Get(string key, int defaultValue) {...}
bool Get(string key, bool defaultValue) {...}

当然,会有一些重复,但编译器将能够针对每个单独的场景进行优化 - 没有装箱。你甚至可以(如果你选择)用类似的Convert.ChangeType东西替换int.Parse(对于这种T = int情况)。


另一种选择(给定您的示例)是使 memoized 对象通用:

public MySpecialValue<T> {
    T val;
    bool valSet = false; 

    T GetValue() { 
         if (!valSet)
         {
                val = (T)Convert.ChangeType(DatabaseValue, typeof(T));
                valSet = true;
         }
         return val;
     }

     public string DatabaseValue { get; set; }
}

并将<T>代码提升一个级别,以便在演员表中完成。

于 2011-01-19T06:07:54.923 回答
1

考虑Lazy<T>为此使用。

因此,如果您有某种属性集合。

public class MyClass 
{
...
}

Public class MyClass<T> : MyClass
{
  T val;
  bool valSet; 
  public T GetValue<T> () { 
        if (!valSet)
        {
            val = (T)Convert.ChangeType(DatabaseValue, typeof(T))};
            valSet = true;
        }
        return val;
    }
}

大概你的父类中有一个通用方法

class SomePropertyBag{

private Dictionary<string, MyClass> dict;

T GetValue<T>(string name, T default)
{
  MyClass res;
  if(!dict.TryGetValue(out res))
  {
     res = new MyClass<T>(name);
     dict.Add(name, res);
  }
  return ((MyClass<T>)res).GetValue();
}
于 2011-01-19T01:32:26.120 回答
0

这使得值类型的东西稍微快一点(没有拆箱)......并且对于 ref 类型的额外调用稍微慢一点......但是有点奇怪。

 class MyClass {
    class Container<T>
    {
        public T Value { get; set; }
    }

    bool valSet;
    object val; 

    public T GetValue<T> () { 
        if (!valSet)
        {
            val = new Container<T>{Value =  (T)Convert.ChangeType(DatabaseValue, typeof(T))};
            valSet = true;
        }
        return ((Container<T>)val).Value;
    }

    public string DatabaseValue { get; set; }
 }
于 2011-01-19T02:28:23.710 回答