Can a C# lambda expression ever return void?

故事扮演 提交于 2019-11-30 18:32:12

I refer you to section 7.1 of the specification, which states:

[An expression may be classified as] "nothing". This occurs when the expression is an invocation of a method with a return type of void. An expression classified as nothing is only valid in the context of a statement expression.

[Emphasis added].

That is to say that the only time you may use an expression which is a void-returning method invocation is when the expression makes up an entire statement. Like this:

M();

This is, in effect, a violation of functional programming rules. This has the same flaw Eric Lippert described about List.ForEach: You're philosphically trying to cause side effects on your collection.

Enumerable.Select is intended to return a new collection - filtering the input. It is not intended to execute code.

That being said, you can work around this by doing:

defaults.Where(item => item.Key.Invoke(configuration)).ToList().ForEach( item => item.Value.Invoke(configuration));

It's just not as clear as doing:

var matches = defaults.Where(item => item.Key.Invoke(configuration));
foreach(var match in matches)
    match.Value.Invoke(configuration);

Firstly, you should really avoid putting side-effects in standard linq query operators, and secondly this won't actually work since you aren't enumerating the Select query anywhere. If you want to use linq you could do this:

foreach(var item in defaults.Where(i => i.Key.Invoke(configuration)))
{
   item.Value.Invoke(configuration);   
}

Regarding your question, I'm pretty sure there are no possible values of void and you can't return it explicity. In functional languages such as F#, void is replaced with 'unit' i.e. a type with only one possible value - if you wanted you could create your own unit type and return that. In this case you could do something like this:

defaults.Select(item => {
    if(item.Key.Invoke(configuration))
    {
        item.Value.Invoke(configuration);
    }
    return Unit.Value;
}).ToList();

But I really can't recommend doing this.

From a language standpoint, void means "does not exist", which begs the question: what value would there be in declaring a variable that does not exist?

The problem here is not a language limitation but the fact that you're using a construct (the ternary operator) that demands two rvalues -- where you only have one.

If I may be blunt, I'd say you're avoiding if/else in favor of pointless brevity. Any tricks you come up with to replace default(void) will only serve to confuse other developers, or you, in the future, long after you've stopped bothering with this sort of thing.

default doesn't work with void; but it works with a type. The Action class produces no result, but the Func<> object always has to return a result. Whatever item.Value.Invoke() returns just return the default of that, as in:

default(object)

or if it's a specific type:

default(SomeType)

Like that.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!