Как рефакторизовать один и тот же блок кода делегата в один приватный метод?

Как рефакторизовать один и тот же блок кода делегата в один приватный метод?
Как рефакторизовать один и тот же блок кода делегата в один приватный метод? - macrimihail @ Unsplash

У меня есть эти строки в нескольких тестовых методах. Теперь я пытаюсь создать приватный метод для очистки, но не уверен, как это сделать. Любое предложение или указатель были бы очень полезны. Спасибо.

    var actualValiationString = string.Empty;
    void messageBuilder(string validationString)
        => actualValiationString = validationString;
    var validationDelegate = new Action<string>(messageBuilder);

Вот как выглядят реальные тестовые методы:

[Theory]
[MemberData(nameof(TryGetBoolTestData))]
public void TryGetBoolShouldReturnBool(
    Dictionary<string,string> metadata,
    bool expectedValue,
    string expectedValidationString
)
{
    var actualValiationString = string.Empty;
    void messageBuilder(string validationString)
        => actualValiationString = validationString;
    var validationDelegate = new Action<string>(messageBuilder);


    DictionaryExtensions.TryGetBool(
        metadata,
        MetadataKey,
        out var response,
        validationDelegate
    );


    response.Should().Be(expectedValue);
    actualValiationString.Should().Be(expectedValidationString);
}

[Theory]
[MemberData(nameof(GetBoolTestDataWithDefaultValueAndAction))]
public void GetBoolWithDefaultValueAndActionShouldReturnBool(
    Dictionary<string, string> metadata,
    bool defaultValue,
    bool expectedValue,
    string expectedValidateString
)
{
    var actualValiationString = string.Empty;
    void messageBuilder(string validationString)
        => actualValiationString = validationString;
    var validationDelegate = new Action<string>(messageBuilder);


    var actualValue = DictionaryExtensions.GetBool
    (
        metadata,
        MetadataKey,
        defaultValue,
        validationDelegate
    );


    actualValue.Should().Be(expectedValue);
    actualValiationString.Should().Be(expectedValidateString);
}

Объедините делегат и локальную переменную в классе:

class Validator
{
    public string ActualValidationString { get; private set; } = string.Empty;
    public void Validation(string msg)
    {
        ActualValidationString = msg;
    }
}

Теперь вы можете использовать его таким образом:

var validator = new Validator();

var actualValue = DictionaryExtensions.GetBool
(
    metadata,
    MetadataKey,
    defaultValue,
    validator.Validation
);


actualValue.Should().Be(expectedValue);
validator.ActualValidationString.Should().Be(expectedValidateString);

Использование класса, вероятно, является наиболее идиоматичным решением в C#. Но если вы действительно настаиваете на "единственном приватном методе", можно также реализовать это в терминах двух закрытий, разделяющих общую переменную:

 static (Action<string>, Func<string>) CreateValidator()
 {
     string actualString=string.Empty;
     return (s => actualString=s , () => { return actualString;});
 }

Это должно быть использовано таким образом:

var validator = CreateValidator();

var actualValue = DictionaryExtensions.GetBool
(
    metadata,
    MetadataKey,
    defaultValue,
    validator.Item1
);

actualValue.Should().Be(expectedValue);
validator.Item2().Should().Be(expectedValidateString);

Это решение немного короче, чем первое, но может быть - спорно - немного сложнее для понимания, если человек не привык к функциональному программированию.Это решение


LetsCodeIt, 3 марта 2023 г., 19:19