Ok, i have a need to be able to keep track of value type objects which are properties on another object, which cannot be done without having those properties implement an IObservable interface or similar. Then i thought of closures and the famous example from Jon Skeet and how that prints out 9 (or 10) a bunch of times and not an ascending order of numbers. So i thought why not do this:
Class MyClass
{
...
Func<MyValueType> variable;
...
public void DoSomethingThatGetsCalledOften()
{
MyValueType blah = variable(); //error checking too not shown for brevity
//use it
}
...
}
... in some other consuming code ...
MyClass myClass = new MyClass();
myClass.variable = () => myOtherObject.MyOtherProperty;
//then myClass will get the current value of the variable whenever it needs it
Obviously this would require some understanding of how closures work, but my question is this: is this a good idea or a dirty hack and a misuse of the closure system?
Edit: Since some people seem to be misunderstanding what i'm trying to say, here's a console program which demonstrates it:
using System;
using System.Linq;
namespace Test
{
class Program
{
public static void Main()
{
float myFloat = 5;
Func<float> test = () => myFloat;
Console.WriteLine(test());
myFloat = 10;
Console.WriteLine(test());
Console.Read();
}
}
}
That will print out 5
then 10
.
You would need to type your
variable
member asFunc<MyValueType>
(or anotherdelegate
that returnsMyValueType
), but you wouldn't be able to assign the value ofblah
in that manner. Just as with using the closure in theforeach
loop above, it's only going to evaluate at a point in time. This isn't a way to keep your variable's value in sync with the other object. There is, in fact, no way to do that without either:Timer
You would be able to implement a property like that (since a property is evaluated at every call), but then what's the sense in using a custom delegate, other than the fact that you don't have to know anything about the other instance.
Edit
I'll try to make this a little clearer. Using this code that you posted:
First, for this to be functional,
variable
should beFunc<MyValueType>
, notAction<MyValueType>
(Func
returns a value,Action
does not; since you're trying to assign a value to a variable, you need the expression to return a value).Second, the main issue with your approach is--assuming I'm reading your code correctly--you're attempting to assign the value of the instance variable
blah
to the evaluated value ofvariable()
within the class declaration. This won't work for a couple of reasons:variable
is)NullReferenceException
upon instantiating your object, since it would be trying to evaluatevariable
, which would benull
at that timeblah
would still only represent the evaluated value ofvariable()
at whatever time it was evaluated. It would not "point to" that function and be automatically kept in sync, as it seems like you're trying to do.If you aren't looking for some sort of automatic synchronization, then there's nothing stopping you from just keeping the
Func<MyValueType>
delegate around to evaluate; there's nothing particularly good or bad about that approach, and it isn't a closure unless the delegate (in your case a lambda expression) involves the use of a local variable.You have stumbled upon the famous koan: Closures are a poor man's object. You are using
Action<T>
to substitute for a property getter of typeT
. Such a thing would be (slightly) less of a dirty trick in a more dynamic language, since it could be implemented by injecting a getter that’s decorated with your logging function, but in C# there isn’t an elegant way to monkeypatch someone’s property when they’re not expecting it.As a mechanism for obtaining the value fro a property, it'll work (but it won't provide any mechanism for noticing updates promptly). However, it depends on how you intend to use it. To do this conveniently you'll need to use a pile of lambdas in the code, or have some
DynamicMethod
/Expression
code do it at runtime. In most cases, something more similar to reflection would be more convenient.I wouldn't necessarily worry about the "value type" aspect; in most cases this isn't a bottleneck, despite the FUD - and it is generally a lot easier to handle such code with
object
than it is via generics or similar.I have some code in my IDE that demonstrates
DynamicMethod
vs raw reflection (that I intend to blog some day soon), showing how reflection-based code doesn't have to be slow (or just useHyperDescriptor
).The other option is to implement the correct interfaces / add the correct events. Perhaps via PostSharp, perhaps via dynamic types (inheriting and overriding at runtime), perhaps with regular code.