Причина предупреждения объясняется в разделе The issue with T?
документа Попробовать ссылку, допускающую значение NULL Виды. Короче говоря, если вы используете T?
, вы должны указать, является ли тип классом или структурой. Вы можете создать два типа для каждого случая.
Более глубокая проблема заключается в том, что использование одного типа для реализации Result и удержания значений Success и Error возвращает те же проблемы, которые должен был исправить Результат, и несколько других.
- Один и тот же тип должен нести мертвое значение, либо тип, либо ошибку, либо возвращать нули.
- Сопоставление с образцом для типа невозможно. Чтобы это сработало, вам придется использовать несколько причудливых выражений сопоставления с позиционным образцом.
- Чтобы избежать нулей, вам придется использовать что-то вроде Option / Maybe, похожее на Параметры. Тем не менее, вы все равно будете носить с собой None либо для значения, либо для ошибки.
Результат (и любой) в F #
Отправной точкой должен быть тип результата F # и размеченные объединения. . В конце концов, это уже работает в .NET.
Тип результата в F #:
type Result<'T,'TError> =
| Ok of ResultValue:'T
| Error of ErrorValue:'TError
Сами типы несут только то, что им нужно.
DU в F # допускают исчерпывающее сопоставление с образцом, не требуя нулей:
match res2 with
| Ok req -> printfn "My request was valid! Name: %s Email %s" req.Name req.Email
| Error e -> printfn "Error: %s" e
Эмуляция в C # 8
К сожалению, в C # 8 еще нет DU, они запланированы для C # 9. В C # 8 мы можем эмулировать это, но мы теряем исчерпывающее сопоставление:
#nullable enable
public interface IResult<TResult,TError>{}
struct Success<TResult,TError> : IResult<TResult,TError>
{
public TResult Value {get;}
public Success(TResult value)=>Value=value;
public void Deconstruct(out TResult value)=>value=Value;
}
struct Error<TResult,TError> : IResult<TResult,TError>
{
public TError ErrorValue {get;}
public Error(TError error)=>ErrorValue=error;
public void Deconstruct(out TError error)=>error=ErrorValue;
}
И используйте это:
IResult<double,string> Sqrt(IResult<double,string> input)
{
return input switch {
Error<double,string> e => e,
Success<double,string> (var v) when v<0 => new Error<double,string>("Negative"),
Success<double,string> (var v) => new Success<double,string>(Math.Sqrt(v)),
_ => throw new ArgumentException()
};
}
Без исчерпывающего сопоставления с образцом мы должны добавить это предложение по умолчанию, чтобы избежать предупреждений компилятора.
Я все еще ищу способ получить исчерпывающее сопоставление без введения мертвых значений, даже если они всего лишь Option.
Вариант / Возможно
Создание класса Option с использованием исчерпывающего сопоставления проще:
readonly struct Option<T>
{
public readonly T Value {get;}
public readonly bool IsSome {get;}
public readonly bool IsNone =>!IsSome;
public Option(T value)=>(Value,IsSome)=(value,true);
public void Deconstruct(out T value,out bool isSome)=>(value,isSome)=(Value,IsSome);
}
//Convenience methods, similar to F#'s Option module
static class Option
{
public static Option<T> Some<T>(T value)=>new Option<T>(value);
public static Option<T> None<T>()=>default;
}
Что можно использовать с:
string cateGory = someValue switch { Option<Category> (_ ,false) =>"No Category",
Option<Category> (var v,true) => v.Name
};
person
Panagiotis Kanavos
schedule
14.11.2019