The code you give is somewhat bizarre. How does "DoSomethingExpensive" know to return a T for arbitrary T? That makes no sense to me The way you typically write a generic memoizer is like this: public static Func Memoize(this Func func) { bool executed = false; T result = default(T); Func memoized = ()=> { if (!executed) { result = func(); executed = true; } return result; }; return memoized; } And now you can say: Func expensive = DoSomethingExpensiveThatGetsAnInt; Func memoized = expensive.Memoize() And you're done.No boxing required.
The code you give is somewhat bizarre. How does "DoSomethingExpensive" know to return a T for arbitrary T? That makes no sense to me.
The way you typically write a generic memoizer is like this: public static Func Memoize(this Func func) { bool executed = false; T result = default(T); Func memoized = ()=> { if (!executed) { result = func(); executed = true; } return result; }; return memoized; } And now you can say: Func expensive = DoSomethingExpensiveThatGetsAnInt; Func memoized = expensive.Memoize(); And you're done. No boxing required.
Eric ... I agree it is a bit bizarre ... but it has a crazy little use case for us: in our code it is (T)Convert. ChangeType(DatabaseValue, typeof(T)) – Sam Saffron? Jan 19 at 2:24 1 @Sam: I think the question would make a lot more sense if you posed the problem that you actually have rather than trying to make a weird abstract version of it.
– Eric Lippert Jan 19 at 2:29 Eric, I just edited it to reflect the real world problem – Sam Saffron? Jan 19 at 2:35.
If T and the result of Convert. ChangeType are reference types then there will be no unboxing. If Convert.
ChangeType returns a boxed value type and T is a value type then there isn't anything you can do to avoid unboxing if you want GetValue to return T.
Consider using Lazy for this. So if you have some kind of collection of properties. Public class MyClass { ... } Public class MyClass : MyClass { T val; bool valSet; public T GetValue () { if (!valSet) { val = (T)Convert.
ChangeType(DatabaseValue, typeof(T))}; valSet = true; } return val; } } Presumably you then have a generic method in your parent class class SomePropertyBag{ private Dictionary dict; T GetValue(string name, T default) { MyClass res; if(!dict. TryGetValue(out res)) { res = new MyClass(name); dict. Add(name, res); } return ((MyClass)res).GetValue(); }.
Not if val and valSet are private. You don't have to expose the Lazy, you can use it internally. – Neil Jan 19 at 1:36 this kind of breaks for me, I need to be able to put MyClass in a dictonary ... before knowing the type it will eventually contain ... – Sam Saffron?
Jan 19 at 3:31 @Sam - I didn't have the original problem 100% when I wrote this - I see your predicament. I was assuming that SomeLongRunning guy was going to be only dependent on the property name passed in, and no on previously fetched data. That leaves you with 2 dictionaries to implement it this way or your previous way - which is cleaner.
NB you can get rid of your valSet private and replace it with a check for nullness of your val container - since in the case of a null actual value you will havean actual container holding null :) – Neil Jan 19 at 3:41.
I'm willing to bet (OK, I also have the advantage of having the source code...) that in most cases this code is called as per you your examples in your reply Get("Site.Twitter. AccountName", "") or Get("Site.Twitter. AccountName", 77) In which case you are using generic type inference.
But there is another, simpler, thing that would compile there... don't use generics. I expect there are only a few scenarios here; so write a few classes / method-overloads - one for string, one for int, etc. String Get(string key, string defaultValue) {...} int Get(string key, int defaultValue) {...} bool Get(string key, bool defaultValue) {...} Sure, there will be a little duplication, but the compiler will be able to optimise for each individual scenario - no boxing. You could even (if you choose) replace the Convert.
ChangeType with something like int. Parse (for the T = int case). Another option (given your examples) is to make the memoized object generic: public MySpecialValue { 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; } } and push the code up a level, so that is done in a cast.
This makes stuff ever so slightly faster for value types (no unboxing) ... and ever so slightly slower for ref types one extra call ... it is however a bit strange. Class MyClass { class Container { public T Value { get; set; } } bool valSet; object val; public T GetValue () { if (!valSet) { val = new Container{Value = (T)Convert. ChangeType(DatabaseValue, typeof(T))}; valSet = true; } return ((Container)val).
Value; } public string DatabaseValue { get; set; } }.
This is of course a pretty brittle piece of code. If you call GetValue() and then later call GetValue() you will get an exception. Of course it is difficult to know if that is an issue withing this context.
– Neil Jan 19 at 2:44 @Neil, for my context: if somebody does: Get(setting: "Site.Twitter. AccountName", default:""); followed by a Get(setting: "Site.Twitter. AccountName", 77); ... I actually want stuff to explode – Sam Saffron?
Jan 19 at 2:49 Sure - sounds reasonable. Then in that case though the whole of the MyClass could have been generic. I will edit my answer to reflect.
– Neil Jan 19 at 2:58 see added code in my answer - I put it there because it is easier to talk code. – Neil Jan 19 at 3:09.
I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.