我有一个泛型方法,用于记忆db中字符串值的转换为实际转换值。
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; }
}
问题是在初始化期间我不知道数据库中的数据是什么类型,它只能在第一次调用时才能做出这个决定。
有没有办法以这样的方式构造它,以至于它不被强制为缓存的unbox值类型? (不改变包含类的签名)
答案 0 :(得分: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();
你已经完成了。不需要拳击。
答案 1 :(得分:3)
如果T和Convert.ChangeType
的结果是引用类型,则不会取消装箱。
如果Convert.ChangeType
返回一个盒装值类型而T是一个值类型,那么如果你想让GetValue返回T,你就无法做任何事情来避免拆箱。
答案 2 :(得分: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();
}
答案 3 :(得分:1)
我愿意打赌(好吧,我也有使用源代码的优势......)在大多数情况下,这段代码会根据您your reply
中的示例进行调用Get("Site.Twitter.AccountName", "")
或
Get("Site.Twitter.AccountName", 77)
在这种情况下,您使用的是泛型类型推断。但还有另一个更简单的东西可以在那里编译...... 不要使用泛型。我希望这里只有几个场景;所以写一些类/方法重载 - 一个用于string
,一个用于int
等等。
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>
代码提升到某个级别,以便在演员阵容中完成。
答案 4 :(得分: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; }
}