Question

Looking for a way to pass an associative array to a method. I'm looking to rewrite an Actionscript tween package in C# but running into trouble with "associative" arrays/objects. Normally in Actionscript I might do something like:

public function tween(obj:DisplayObject, params:Object = null):void {
    if (params.ease != null) {
        //do something
    }
    //...
}

And this could be called like:

tween(this, {ease:'out', duration:15});

I'm looking for a way to do the same in C#. So far, I've gathered my options to be:

a) creating a class or struct to define the possible param keys and types and pass that

b) pass the parameters as generic type

tween(frameworkElement, new {ease = 'out', duration = 15});

assuming

public static void tween(FrameworkElement target, object parameters);

and figure out some way to use that in the tween function (I'm not sure how to separate the key=value's given that object. any ideas?)

c) create a Dictionary<string, object> to pass the parameters into the tween function

Any other ideas or sample code? I'm new to C#.

Edit

Took me all day to figure this out:

"Anonymous types cannot be shared across assembly boundaries. The compiler ensures that there is at most one anonymous type for a given sequence of property name/type pairs within each assembly. To pass structures between assemblies you will need to properly define them."

Was it helpful?

Solution

EDIT: This is basically the mechanism that HtmlHelper extensions use in ASP.NET MVC. It's not original with me.


I'd favor a hybrid approach that has two different signatures. Note: I haven't tried this and there may be a conflict between the two signatures so you may have to give the second method a slightly different name to allow the compiler to choose between them, but I don't think so.

public static void tween( FrameworkElement target, object parameters )
{
    return tween( target, new ParameterDictionary( parameters ) );
}

public static void tween( FrameworkElement target,
                          ParameterDictionary values )
{
    if (values.ContainsKey( "ease" ))
    {
      ....
    }
}

Then you have a ParameterDictionary class that uses reflection on the anonymous type and sets up the dictionary.

public class ParameterDictionary : Dictionary<string,object>
{
    public ParameterDictionary( object parameters )
    {
         if (parameters != null)
         {
             foreach (PropertyInfo info in parameters.GetType()
                                                     .GetProperties())
             {
                 object value = info.GetValue(parameters,null);
                 this.Add(info.Name,value);
             }
         }
    }
}

This gives you both ease of use and ease of consumption -- the "ugly" reflection stuff is wrapped up in the single constructor for the dictionary rather than in your method. And, of course, the dictionary can be used over and over for similar purposes with the reflection code only written once.

OTHER TIPS

The Dictionary is a reasonable approach. It might look like this:

public static void tween(FrameworkElement target, IDictionary<string, object> parameters)
{
    if (parameters.ContainsKey("ease")) {
        //do something
    }
}

Mind that when you pass the values in, you can use shortened collection initialization syntax to make it easier, like:

tween(something, new Dictionary<string, object> { { "ease", "out" }, { duration, 15 } });

This would be a pretty quick way to do roughly "the same thing" as the ActionScript code, but it's not really great C#. The C#-ish way to do it would be to make a real TweenParameters struct or class with properties for each possible parameter, and then create one to pass into tween(). This is generally considered more maintainable, since all the "available" properties are obvious to a caller without looking into the internals of tween(), and because it catches errors at compile-time that a string comparison wouldn't notice until runtime, like typoing "duration" "duratoin".

I'm a fan of option (b) myself - passing an anonymous type and parsing out the values using reflection.

I've seen others achieve the same thing using lambda expressions. The calling syntax would be:

tween(frameworkElement, ease => "out", duration => 15);

And the declaration would be something along the lines of:

public static void tween(FrameworkElement target, params Expression<Func<object>>[] parameters) { ... }

The idea is that you can take a variable number of "functions which return object". You then parse the name of the parameter out of each Expression<TDelegate>, and invoke each one to get its value.

I don't think this is any better than reflecting over an anonymous type, but it's another approach to consider.

Update

I have actually written about the idea of passing associative arrays as dictionaries on my blog, here and here.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top