• Advertisement
Sign in to follow this  

C# Variable binding

This topic is 1078 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have come across this several times, I haven't got a good solution yet.

 

I often come across variable binding in C++. The code is generally of the form....

PropertyManager::BindVariable(const char * name, void * object);


Then when you want the value you can call the Get function on the property manager and get an up to date value back.

 

I want to be able to do the same in C#.

 

Effectively what I would like is

Dictionary<String,ref Object>Properties;

Which of course you cannot do in C#

 

In the past what I have done is ...

Dictionary<String,Action>variables;

But then I have to define a get function for every variable. It works but it's a lot of boring work when you are porting from c++ (god I would love to have #define back. It's about the only thing I miss)

 

Has anyone come up with a better solution?

 

 

 

 

Share this post


Link to post
Share on other sites
Advertisement
I'm not entirely sure what you actually want from your solution - so the answer would probably be better if you stated what your end goal is.

But I'm guessing what you actually want is to use Reflection.

C++ doesn't have any kind of reflection system, which is what I'm guessing your original code actually does - trying to give a name to a variable so you can access the variable at runtime with a name instead of the variable itself.

With .NET you can simply ask for a type (by name, if necessary), and then ask the type for all the members, properties, and methods it contains, getting type information, and even invoking them.

Keep in mind that, just like your C++ solution, this is slower then if you had direct access to the variables, but sometimes it's the only way to get what you want.

Share this post


Link to post
Share on other sites

No, sorry wrong end of stick.

 

Say you have a block of code that calculates a value. You want this value to be visible to many many other code blocks, without them knowing where it came from.

 

So you have say a hundred variables generated from 50 code blocks and you want to be able to get the current value of any of the variables from a central, globally visible spot.

 

Think of a flight simulatior. You may be flying a jet, or a helicopter, or a piston engined plane, or a balloon, but as far as the system is concerned all it wants to know is "how much fuel was burnt in the last 16.666667 ms".

 

Rather than having to know in advance what systems are in the plane, it is common to have a central data store.

 

You do this by having a PropertyManager which holds pointers to the various variables in a dictionary. So if I want to know how much fuel was burnt in the last frame I just call the property manager with a string something like "systems/propulsion/fuelburntthisframe" and get back a double containing the lbs of fuel burnt.

 

This is one way to do it.

    public class PropertyNode
    {
        public Dictionary<String, Func<float>> floatvariables = new Dictionary<string, Func<float>>();

    }
    class Program
    {
        public static float fred;

        public static float GetFred()
        {
            return fred;
        }
        static void Main(string[] args)
        {
            PropertyNode props = new PropertyNode();
            Func<float> gf = GetFred;
            props.floatvariables.Add("fred", gf);
            fred = 12;
            System.Diagnostics.Debug.WriteLine(String.Format("Fred = {0} should be 12",props.floatvariables["fred"]()));
            fred = 24;
            System.Diagnostics.Debug.WriteLine(String.Format("Fred = {0} should be 24",props.floatvariables["fred"]()));
            fred = 36;
            System.Diagnostics.Debug.WriteLine(String.Format("Fred = {0} should be 36",props.floatvariables["fred"]()));


        }
    }

which produces the expected output

 

Fred = 12 should be 12
Fred = 24 should be 24
Fred = 36 should be 36

 

The trouble with that is that when I am porting from C++ I would have to take a line of code similar to this.

TIE("tow/length", SGRawValuePointer<float>(&_towLength));

and replace it with

public float GetTowLength()
{
     return _towLength;
}


............

PropertyNode n =  new PropertyNode(object_name);
Func<float>GTL = GetTowLength;
n.floatvariables.Add("tow/length",GTL);

While that is not that painful, when you have a lot of variables, it becomes a real pain in the posterior.

 

I'm just hoping someone out there has come up with a better way of doing it.

Share this post


Link to post
Share on other sites

You appear to have simply built a poor man's version of the C# PropertyInfo (or FieldInfo) class there. If you store those, you don't have to write "wrapper functions" to get and set the value of every field or property (properties, in fact, are little more than fields with wrapper get and set functions you define).

 

That said, without a more practical example, it feels like you're trying to overengineering this solution since if you know you want to find "systems/propulsion/fuelburntthisframe" every time, you could pretty easily codify that into the actual type of the object you're using so you don't need to bother with all this reflection muckery.

Edited by Josh Petrie

Share this post


Link to post
Share on other sites
You could also make a generic value-container class. I generally don't like this pattern, but it can do what you want.

public class Value<T>
{
    T value;

    // implicit conversion operators to/from T, etc...
}
From that point on, since it's a class, you can store as many references to Value objects (and therefore have quick access to the actual value inside it) as you want.

Share this post


Link to post
Share on other sites

Like Josh said, it sounds like you want a dictionary of string -> (object, FieldInfo) pairs   (or (object, PropertyInfo)).

 

Using the object and the FieldInfo, you can get the value of that field on a particular object.

 

Use the reflection APIs to get the FieldInfo for an object.

 

Type type = objectThatHasFred.GetType();

FieldInfo fieldInfo = type.GetField("Fred");

// Then store "Fred" -> (objectThatHasFriend, fieldInfo) in your dictionary.

Share this post


Link to post
Share on other sites
I'm not sure I follow your example.

You set up global variables, and then want to access them by strings? Via a global "manager" class? Just sounds like a design disaster waiting to happen.

I think you're looking at it wrong. If I was writing a simulator, I'd have some sort of "fuel provider" which I would give to the "engine" and anything else that used fuel. Then when the "engine" needed fuel, it would ask for some. Then in my "plane" I would make a "fuel tank" which implements "fuel provider" and give it to the "engine" to use.

Heck, if you wanted to go really fancy with your simulator, you'd have a "fuel hose" connected to a "fuel pump" connected to a "fuel tank" - all of which implement "fuel provider". That's not something you could do with your named global variables example.

No global variables, much more flexible, and means I can do things like have more then one airplane in the game at a time ;) Edited by SmkViper

Share this post


Link to post
Share on other sites

It appears you want string-keyed globals or something like the observer pattern.

 

I can't really offer any improvements on your overall design, but a few notes.

You don't need to store the function in a local delegate, you can pass it directly.

props.floatvariables.Add("fred", GetFred);

Or you can use lambda expressions:

props.floatvariables.Add("fred", () => fred);

You could also add an indexer to the PropertyNode class to simplify access:

public float this[string key]
{
    get
    {
        return floatvariables[key]();
    }
}

Share this post


Link to post
Share on other sites

You set up global variables, and then want to access them by strings? Via a global "manager" class? Just sounds like a design disaster waiting to happen.

 

I'm not designing the code, meerly porting it. My own flight dynamics model uses a completely different system.

 

This design methodoligy is common and used in most flight dynamic models because of the massive variation in the systems you are trying to emulate. Just think about how many different engines there have been in aircraft in the last 100 years, never mind all the other systems. Then think about the fact that an aircraft can have a variable number of engines ( how many did the grey goose have ? was something like 18 wasn't it ?).

 

Here is an example comment from one FDM I am porting so you can see the sort of usage.

    /**
     * Tie a property to a pair of object methods.
     *
     * Every time the property value is queried, the getter (if any) will
     * be invoked; every time the property value is modified, the setter
     * (if any) will be invoked.  The getter can be 0 to make the property
     * unreadable, and the setter can be 0 to make the property
     * unmodifiable.
     *
     * @param name The property name to tie (full path).
     * @param obj The object whose methods should be invoked.
     * @param getter The object's getter method, or 0 if the value is
     *        unreadable.
     * @param setter The object's setter method, or 0 if the value is
     *        unmodifiable.
     * @param useDefault true if the setter should be invoked with any existing
     *        property value should there be one; false if the old value should be
     *        discarded; defaults to true.
     */

I will have a look at PropertyInfo and FieldInfo, they look promising. Thanks.

 

Initially I tried using an Object, but a float pointer is not an Object. (it's all unsafe code)

Edited by Stainless

Share this post


Link to post
Share on other sites

Initially I tried using an Object, but a float pointer is not an Object. (it's all unsafe code)

 

 

 

That's an important requirement you omitted from your original problem description. Build an object that wraps the unmanaged pointers and store that (dealing with unsafe code will often require these sorts of things).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement