1

I need to call a delegate method passed as a parameter, but since this parameter is optional I want to set the default value to a method implemented in the "destination" class.

This is an example where it almost works as expected:

public class AgeCalculator
{
    public void SetAge(Client client, Func<int, int> getAge = default(Func<int, int>))
    {
        client.Age = getAge != default(Func<int, int>) ? getAge(client.Id) : this.getAge(client.Id);
    }

    private int getAge(int clientId) {
        return 10;
    }
}

And then..

class Program
{
    static void Main(string[] args)
    {
        AgeCalculator calculator = new AgeCalculator();

        Client cli1 = new Client(1, "theOne");

        calculator.SetAge(cli1);//Sets 10
        calculator.SetAge(cli1, getAge);//Sets 5
    }

    private static int getAge(int clientId) {
        return 5;
    }
}

The question now; what is the default value that has to be setted to avoid asking about the delegate value?

Tried "public void SetAge(Client client, Func getAge = this.getAge)" with no luck.

Is there a tag or different definition needed on AgeCalculator.getAge?, should I use dynamic methods?

Thanks in advance.

Note: The real scenario involves more complex logic in a TDD oriented project, this is a sample to summarize the situation.

Felipe Pereira
  • 11,410
  • 4
  • 41
  • 45

2 Answers2

7

Default values for method arguments must be compile-time constants. Writing default(Func<...>) is just verbose syntax for null, which is the default value for reference types (as a delegate, Func is a reference type) and the only default value you can use in this context.

However, you can do much better with the old-fashioned way of offering two overloads for the method:

public void SetAge(Client client)
{
    // Select any default value you want by calling the other overload with it
    SetAge(client, this.getAge);
}

public void SetAge(Client client, Func<int, int> getAge)
{
    client.Age = getAge(client.Id);
}
Jon
  • 428,835
  • 81
  • 738
  • 806
  • Hi, that is correct, but it doesn't answer my question. It would be a useful tip if I wanted to print this code and save some ink using "null" instead of "default(Func<..>)". – Felipe Pereira Aug 14 '13 at 20:39
  • @FelipePereira: I 'm not sure what that means. The *only* default you can use in the parameter list is `null`, and then you are reduced to detecting that and substituting some other value exactly as in your example. There is no other option. – Jon Aug 14 '13 at 20:41
  • I was commenting based on your first answer (unedited I guess), where only the verbose issue was mentioned. Now with the overloaded way, it's totally valid here, but in the real scenario (unknown to all here, I know) the best option would be a optional param. Let me get more info about it and I'll update the question with more relevant data about existing limitations. Thanks – Felipe Pereira Aug 14 '13 at 20:52
1

This is basically doing what you are asking, the only thing is that the hints given by VS won't show that a function is being used as the default if null isn't used. If that isn't a problem then this solution is logically as close as you are going to get.

public class AgeCalculator
{
    public void SetAge ( Client client , Func<int , int> getAge = null)
    {
        // assigns this.getAge to getAge if getAge is null
        getAge = getAge ?? this.getAge;
        client.Age = getAge( client.Id );
    }

    private int getAge ( int clientId )
    {
        return 10;
    }
}

You can also make this something that allows a variable method to be plugged in if you want to change the default setter dynamically. It is identical logic just another way, this is beneficial if you know you will use the same function multiple times in a row.

public class AgeCalculator
{
    public void SetAge ( Client client )
    {
        client.Age = GetAge( client.Id );
    }

    private Func<int,int> _getAge;
    public Func<int,int> GetAge 
    {
            private get
            {
                if(_getAge == null)
                    _getAge = getAge;
                return _getAge;
            }
            set
            {
                if(value == null)
                    _getAge = getAge;
                else
                    _getAge = value;
            }
    }

    private int getAge ( int clientId )
    {
        return 10;
    }
}

//assume we are in main
var cl = new Agecalculator();
var client = new Client(1,"theOne");
var client2 = new Client(2,"#2");

cl.SetAge(client); //set 10
cl.GetAge = getAge;
cl.SetAge(client); //set 5
cl.SetAge(client2); //set 5
konkked
  • 3,161
  • 14
  • 19
  • In the question scope both answers are valid choices to achieve the goal (this and the previous one), but since only one can be marked as correct.., I'll pick this one since it mentions the pattern that I end up using. With the "plugin method" pattern I get the "same function multiple times in a row" benefit that in this TDD oriented project is not a minor issue. Thank you all. – Felipe Pereira Aug 15 '13 at 15:14