Anonymous method should return a string by condition

740 Views Asked by At

I'm trying to understand writing anonymous Methods in C#. But having trouble to achieve a success.

Please have a look at my example. I'm trying to fill a property named Value by given conditions.

When I would write a private helper method which takes an inputparam int lockCardStatus and returns a string that would be a solution but my intention is to try this with a "quickshot" like so:

MailMessageTextPlaceholders = new List<MailMessageTextPlaceholder>
{
    new MailMessageTextPlaceholder
    {
        PlaceholderName = "status",
        Value = y => 
        {
            switch (_lockCard.Status)
            {
                case (int)LockCard.LockCardStatus.Done :
                    return "Is Done";
                case (int)LockCard.LockCardStatus.Pending :
                    return "Is in Pending status";
                case (int)LockCard.LockCardStatus.Open :
                    return "Has been created";
                default:
                    return "No status yet!";
            }
        }
    }
}

Unfortunately the compiler says:

Lambda Expression cannot be converted to type string because it is not a delgate.

2

There are 2 best solutions below

10
Mong Zhu On BEST ANSWER

The error arises because the compiler interprets this line:

Value = y => {...}

as an assignment. It thinks you want to assign the lambda expression to Value. But the types don't match! Value is a string and not a delegate of any kind. For detailed information see Compiler Error CS1660

What you actually want is to execute this lambda and assign the resulting value. To accomplish that you can define the delegate and the return value at creation of the lambda using Func<string>. and execute it on the spot by using the ( ) parentheses like in a normal method call:

MailMessageTextPlaceholder hodler = new MailMessageTextPlaceholder()
    {
        Value = new Func<string>(() =>
        {
            switch (_lockCard.Status)
            {
                case (int)LockCard.LockCardStatus.Done:
                    return "Is Done";
                case (int)LockCard.LockCardStatus.Pending:
                    return "Is in Pending status";
                case (int)LockCard.LockCardStatus.Open:
                    return "Has been created";
                default:
                    return "No status yet!";
            }
        })() // <- this executes the method!
    };

And suddenly this stuff becomes compileable.

EDIT:

Apparently the compiler is not able to infer the return type and thus specify the delegate type on its own. This can be illustrated by this example:

var asd = () => { return "XXX"; };

This line results in the error:

CS0815 Cannot assign lambda expression to an implicitly-typed variable

But excplicit specification of the delegate type resolves this error:

var asd = new Func<string>(() => { return "XXX";});

This indicates that the explicit specification of the delegate type is necessary and essential.

1
mortb On

What you are trying to do is not available (yet) in C# since switch statements cannot be evaluated unambiguously to one return value. A reason for this is that switch cases may contain any arbitrary code and not just one expression.

There will be a new way of writing switch statements in C# 8 that makes your code possible.

You may solve your problem by creating a helper method:

MailMessageTextPlaceholders = new List<MailMessageTextPlaceholder>
{
    new MailMessageTextPlaceholder
    {
        PlaceholderName = "status",
        Value = GetStatusDescription(_lockCard.Status)
    }
}

string GetStatusDescription(LockCard.LockCardStatus status)
{
     switch (status)
     {
        case (int)LockCard.LockCardStatus.Done :
             return "Is Done";
        case (int)LockCard.LockCardStatus.Pending :
             return "Is in Pending status";
        case (int)LockCard.LockCardStatus.Open :
              return "Has been created";
        default:
              return "No status yet!";
    }
}

and the helper method may be a local function

If you still really, really wish to inline your string mapping you may nest ternary operator statements.

MailMessageTextPlaceholders = new List<MailMessageTextPlaceholder>
{
    new MailMessageTextPlaceholder
    {
        PlaceholderName = "status",
        Value = 
           status == LockCard.LockCardStatus.Done
               ? "Is Done";
               : status == LockCard.LockCardStatus.Pending 
                  ? "Is in Pending status"
                  : status == LockCard.LockCardStatus.Open 
                      ? "Has been created"
                      : "No status yet!";
    }
}

When you are using ternary operators, C# will be able to unambiguously evaluate the result, which makes the compiler happy.

You may also solve your problem by adding description attributes to your enum