简体   繁体   中英

Lambdas in Base Constructor Call

Okay, so I have the following base class:

public partial class InputValidator<T> : UserControl {
    public InputValidator(TryParse<T> parserMethod, T initialValue) { }
    public T Value { get; set; }
    public bool IsInputValid { get; }
    public override string Text { get; set; }
    public string InputInvalidMessage { get; set; }
    public TryParse<T> Parser { get; set; }
}

where TryParse<T> is a delegate that represents a method like all the TryParse methods for the built-in types. public delegate bool TryParse<T>(string input, out T result);

The above class is a text-input control that attempts to parse user input using the specified parsing method, and when it can't parse the input, it displays a message below the text box indicating that the user's input is invalid.

I Now have the following which derives from this class:

public class StructInputValidator<T> : InputValidator<T?> where T : struct
{
    public StructInputValidator(TryParse<T> parser, T? initialValue) 
        : base((string text, out T? result) => {
            T nonNullableResult;
            bool parseSuccessful = parser(text, out nonNullableResult);
            if (!parseSuccessful) result = null;
            else result = nonNullableResult;
            return parseSuccessful;
        },
        initialValue) { }
}

The above class takes a non-nullable struct as its type parameter and derives from InputValidator<T?> . The purpose of this derived class is to take a TryParse method for a non-nullable struct and give you an input validator control for the corrasponding nullable struct, such that when the input is invalid the Value property will be set to null. The way it does this is to accept a TryParse delegate in the constructor, and then to pass in a lambda expression of type TryParse to the base class constructor.

As you can see, the lambda expression required to convert a TryParse<T> delegate into a TryParse<T?> delegate is just long enough to be really ugly in a call to a base constructor.

My question is: What is considered the standard "best practice" in the scenerio where you have a lambda expression in a call to a base constructor like this? I can't pass in an instance method that uses the Parser property because the base constructor runs BEFORE that property is initialized. I can't pass in a static method that takes the non-nullable TryParse<T> delegate because then its signature wouldn't match the signature of TryParse<T?> .

Yeah, that's not pretty... But you can use a helper method, like this:

public class StructInputValidator<T> : InputValidator<T?> where T : struct
{
    public StructInputValidator(TryParse<T> parser, T? initialValue) 
        : base(ToNullableTryParse(parser), initialValue)
    { }

    private static TryParse<T?> ToNullableTryParse(TryParse<T> parser)
    {
        return (string text, out T? result) => {
            T nonNullableResult;
            bool parseSuccessful = parser(text, out nonNullableResult);
            result = parseSuccessful ? (T?)nonNullableResult : null;
            return parseSuccessful;
        };
    }
}

Write a static method that is the implementation, and call it from your lambda:

public static bool InvokeParser(string text, out T? result, TryParse<T> parser)
{
    T nonNullableResult;
    bool parseSuccessful = parser(text, out nonNullableResult);
    if (!parseSuccessful) result = null;
    else result = nonNullableResult;
    return parseSuccessful;
}

public StructInputValidator(TryParse<T> parser, T initialValue) 
    : base((string text, out T? result) => InvokeParser(text, out result, parser),
    initialValue) { }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM