Invoke Func which has optional parameters?

2019-08-06 05:15发布

I have various methods which have two optional params, a ConfigSourceType enum and a string representing the filePath and return an instance of "IConfigFile" (Differs depending on the config file).

I'm trying to pass these methods as Func so that I can load configs, but I can't invoke the delegate with no parameters. If I use Type.Missing it still complains about the ConfigSourceType enum being missing.

Edit to include code:

DataHandler class:

    public IConfigFile RetrieveMyConfiguration(
        ConfigurationSourceType source = ConfigurationSourceType.Live,
        string fileName = "")
    {
         /* Irrelevant */
         return new ConfigFile();
    }

Main:

    private void SomeMethod()
    {  
        var dHandler = new DataHandler();
        MyConfig = LoadConfigFile(dHandler.RetrieveMyConfiguration);
    }

    public IConfigFile LoadConfigFile(
            Func<ConfigurationSourceType, string, IConfigFile> func)
    {
        IConfigFile configFile;        
        // Line below doesn't compile:
        configFile = func.Invoke(null, Type.Missing);
        return configFile;
     }

3条回答
聊天终结者
2楼-- · 2019-08-06 05:25

You can't specify optional parameters to a Func<...>, but you can for your own delegates.

This LINQPad example shows how:

void Main()
{
    var t = new Test(XYZ);
    t();
    t(15);
}

public delegate void Test(int a = 10);

public void XYZ(int a)
{
    a.Dump();
}

Output:

10
15

This, however, means that it is the receiving end of a delegate that needs to know about the optional parameters, but it seems you want to specify a delegate for a method and specify optional parameters on the sending end, or inherit optional parameters from the methods that you wrap in the delegate, that's not possible other than to create an anonymous method:

SomeMethod((a, b) => WrappedMethod(a, b, 42));

You could do something like this:

public delegate void MyDelegate(int a, int b, int? c = null, int? d = null);

public void Method(int a, int b, int c = 10, int d = 42) { ... }

new MyDelegate((a, b, c, d) =>
{
    if (c.HasValue && d.HasValue)
        Method(a, b, c.Value, d.Value);
    else if (c.HasValue)
        Method(a, b, c.Value);
    else if (d.HasValue)
        Method(a, b, d: d.Value);
    else
        Method(a, b);
});

But this is starting to get ludicrous.

So no, you can't really easily do what you want.

查看更多
Summer. ? 凉城
3楼-- · 2019-08-06 05:26

There are no optional in Func You'll have to wrap it:

public class Foo
{
    public int Boo(int A = 0, int B = 1)
    {
        return A + B;
    }
}

var foo = new Foo();

var method = (Func<int, int, int>) (foo.Boo);
var methodWrapped = (Func<int, int, int>) ((a, b) => foo.Boo(a, b));
var methodWrappedWithA = (Func<int, int>) ((a)=>foo.Boo(a));
var methodWrappedWithB = (Func<int, int>)((b) => foo.Boo(B:b));
var methodWrappedNoAorB = (Func<int>) (()=>foo.Boo());
查看更多
唯我独甜
4楼-- · 2019-08-06 05:27

Delegates/Func and methods are different things. A Func cannot have optional parameters; that's only a feature of methods.

As an alternative, you could put all parameters into a dedicated class, ConfigFileDescriptor or something, and make the parameters optional in the constructor. You could then use Func<ConfigFileDescriptor, IConfigFile>. However, this solution would require a bit more typing because of the necessary object creation.

查看更多
登录 后发表回答