tags:

views:

66

answers:

3

We have a system where we need to dynamically change what happens at the end of a set of steps. We're doing this using a delegate. However the methods that we need to call at the end of the set of steps have different signatures. We have a choice at the moment to either do this using a standard delegate signature (probably copying the event handler one from ASP.Net) or doing it some other way (undertermined!) Is there a way to do this with delegates in .Net 3.5 ? Or could we do this using C# 4.0's named parameters or optional parameters on the delegate?

A: 

For "normal" methods, you can pass in an open array of parameters, for example:

public void Test(params string[] string parameters);

You could use an open array of Objects. I don't know if this would work for delegates as well and also, you'd lose type safety.

You might create "state objects" that contain different properties with parameters for each invoked method and the method would only take one parameter.

public class StateObject1
{
    public string parameter1;
    public int parameter2;
}

public class StateObject2
{
    public DateTime parameter1;
    public DateTime parameter2;
}

public void Handler1(object stateObject)
{
    if (!(stateObject is StateObject1))
        throw new ArgumentException("Invalid state object type");
    ...
}

public void Handler2(object stateObject)
{
    if (!(stateObject is StateObject2))
        throw new ArgumentException("Invalid state object type");
    ...
}
Thorsten Dittmar
+2  A: 

Your question is quite general. However, I think you could use some general delegate type and then just wrap the call to the final method into a simple lambda expression to convert the parameters appropriately.

For example, let's say that you have an event that fires with two strings as an argument. This may be created using the Action<string, string> delegate from .NET 3.5. Then you'll have two methods that you want to call (and you need to choose between them dynamically):

void Foo(int n, string s) { /* expects int as the first parameter */ } 
void Bar(string concatenated) { /* expects concatenated string */ }

Then you can create two action delegates like this:

// Converts parameter to int and calls 'Foo'
Action<string, string> callFoo = (s1, s2) => Foo(Int32.Parse(s1), s2);
// Concatenates parameters and calls 'Bar'
Action<string, string> callBar = (s1, s2) => Bar(s1 + ", " + s2);

The code in lambda expressions serves as a simple adapter that converts the actual parameters to the parameters expected by the method. Now you can dynamically add/remove callFoo and callBar as handlers to the event that you want to handle.

Tomas Petricek
I've used this technique and it's expressive and brief.
Ed Sykes
A: 

We got around this by using the event handler method signature, i.e. our delegate expects (object sender, eventargs e) and we built a custom event args class.

Bernard