3

I have a delegate that takes quite a few parameters like so:

public delegate void MyDelegate(float thereAre, int lotsOf, string parametersIn, int thisDelegate);
public MyDelegate theDelegateInstance;

This gets quite annoying because Visual Studio 2010 doesn't have any sort of auto complete to help a method match a delegate signature. I basically want to be able to write a method that takes only some of (or none of) the parameters of the delegate and just ignores the others because it doesn't use them anyway.

theDelegateInstance += delegate()
{
    Debug.Log("theDelegateInstance was called");
};

Or

theDelegateInstance += delegate(float thereAre, int lotsOf)
{
    if(thereAre > lotsOf) Debug.Log("thereAre is way too high");
};

I've found that I can make a method take a delegate return a MyDelegate that calls it like so:

public delegate void VoidMethod();

public static MyDelegate ConvertToMyDelegate(VoidMethod method)
{
    return delegate(float thereAre, int lotsOf, string parametersIn, int thisDelegate)
    {
        method();
    };
}

But that requires me to declare a static method for each different conversion.

I just found that I could do my first example without any parameters to achieve the desired result:

theDelegateInstance += delegate//Notice that there are no brackets here.
{
    Debug.Log("theDelegateInstance was called");
};

But that only works for inline methods that take no parameters. If I wanted to use even one of the parameters like the second example, I would need to have all of them.

svick
  • 236,525
  • 50
  • 385
  • 514
SilentSin
  • 1,026
  • 9
  • 18

3 Answers3

1

This can be possible. All you need is to use an optional parameter in your delegate.

Look at Jon Skeet's [answer].

Optional parameters are for use on the calling side - not on what is effectively like a single-method-interface implementation. So for example, this should compile:

delegate void SimpleDelegate(bool x = true);

static void Main()
{
    SimpleDelegate x = Foo;
    x(); // Will print "True"
 }

 static void Foo(bool y)
 {
     Console.WriteLine(y);
 }

(Optional parameters on delegates doesn't work properly).

Community
  • 1
  • 1
aiapatag
  • 3,355
  • 20
  • 24
  • Please include an example in your answer (in addition to a link if you want) rather than having your answer rely on the link. – Servy Jun 06 '13 at 18:58
1

You can always do it with lambdas.

You can do it in two ways - using your two example functions that you want to call:

First way - Create the method, and invoke it directly:

void FirstFunction(float thereAre, int lotsOf)
{
    if(thereAre > lotsOf) 
        Debug.Log("thereAre is way too high");
}

And invoke it this way:

theDelegateInstance += (t, l, p, td) => FirstFunction(t, l);

Second way - just do the call directly without creating the function:

theDelegateInstance += 
    (t, l, p, td) => Debug.Log("theDelegateInstance was called");
Gjeltema
  • 4,122
  • 2
  • 24
  • 31
1

Basically, what you're asking for is a method that returns a lambda like this:

public static MyDelegate ConvertToMyDelegate(VoidMethod method)
{
    return (thereAre, lotsOf, parametersIn, thisDelegate) => method();
}

Fortunately for you, .Net contains a way of creating lambdas programmatically. This means you can create just one generic Convert method, that will handle any number of parameters in both delegate types:

public static TTarget ConvertDelegate<TSource, TTarget>(TSource sourceDelegate)
{
    if (!typeof(Delegate).IsAssignableFrom(typeof(TSource)))
        throw new InvalidOperationException("TSource must be a delegate.");
    if (!typeof(Delegate).IsAssignableFrom(typeof(TTarget)))
        throw new InvalidOperationException("TTarget must be a delegate.");
    if (sourceDelegate == null)
        throw new ArgumentNullException("sourceDelegate");

    var parameterExpressions = typeof(TTarget)
        .GetMethod("Invoke")
        .GetParameters()
        .Select(p => Expression.Parameter(p.ParameterType))
        .ToArray();

    var sourceParametersCount = typeof(TSource)
        .GetMethod("Invoke")
        .GetParameters()
        .Length;

    var expression = Expression.Lambda<TTarget>(
        Expression.Invoke(
            Expression.Constant(sourceDelegate),
            parameterExpressions.Take(sourceParametersCount)),
        parameterExpressions);

    return expression.Compile();
}
svick
  • 236,525
  • 50
  • 385
  • 514