gpt4 book ai didi

c# - 可空引用类型和 Either 模式

转载 作者:太空狗 更新时间:2023-10-30 00:59:32 26 4
gpt4 key购买 nike

我正在试用新的 Nullable Reference Types in C# 8.0 ,我面临以下问题。

给定这个结构:

public readonly struct Either<TReturn, TError>
where TReturn : struct
where TError : struct
{
public TError? Error { get; }
public TReturn? Response { get; }

public Either(TError? error, TReturn? response)
{
if (error == null && response == null)
{
throw new ArgumentException("One argument needs not to be null.");
}
if (error != null && response != null)
{
throw new ArgumentException("One argument must be null.");
}
Error = error;
Response = response;
}
}

我如何告诉编译器要么 Error Response 不为空,并且它们可以不是两者都为空吗?有没有办法用新属性做这样的事情?

最佳答案

结构更新

当结果类型更改为结构时,代码不会更改。要使用结构类型参数,必须将以下约束添加到接口(interface)和类型中:

where TResult : struct
where TError : struct

当我想到 Either 模式时,我想到的是 F#、模式匹配和可区分联合,而不是空值。事实上,Either是一种避免空值的方法。事实上,问题的代码看起来像是试图创建一个 Result type。 ,不仅仅是一个 Either。 Scott Wlaschin 的 Railway Oriented Programming展示了如何使用这种类型在函数式语言中实现错误处理。

在 F# 中,Result类型定义为:

type Result<'T,'TError> = 
| Ok of ResultValue:'T
| Error of ErrorValue:'TError

我们还不能在 C# 8 中这样做,因为没有可区分的联合。这些是为 C# 9 计划的。

模式匹配

我们可以做的是使用模式匹配来获得相同的行为,例如:

interface IResult<TResult,TError>{} //No need for an actual implementation

public class Success<TResult,TError>:IResult<TResult,TError>

{
public TResult Result {get;}

public Success(TResult result) { Result=result;}
}

public class Error<TResult,TError>:IResult<TResult,TError>
{
public TError ErrorValue {get;}

public Error(TError error) { ErrorValue=error;}
}

这样就无法创建 IResult<>这既是成功也是错误。这可以与模式匹配一​​起使用,例如:

IResult<int,string> someResult=.....;

if(someResult is Success<int,string> s)
{
//Use s.Result here
}

简化表达式

给定 C# 8 的 property patterns ,这可以重写为:

if(someResult is Success<int,string> {Result: var result} )
{
Console.WriteLine(result);
}

或者,使用 switch 表达式,典型的铁路式调用:

IResult<int,string> DoubleIt(IResult<int,string> data)
{
return data switch { Error<int,string> e=>e,
Success<int,string> {Result: var result}=>
new Success<int,string>(result*2),
_ => throw new Exception("Unexpected type!")
};
}

F# 不需要 throw因为不可能 Result<'T,'TError>会是 Ok 以外的东西或 Error .在 C# 中,我们还没有该功能。

switch 表达式允许穷举匹配。我认为如果 default 子句也缺失,编译器会生成警告。

带有解构器

如果类型有解构器,表达式可以更简化一点,例如:

public class Success<TResult,TError>:IResult<TResult,TError>
{
public TResult Result {get;}

public Success(TResult result) { Result=result;}

public void Deconstruct(out TResult result) { result=Result;}
}

public class Error<TResult,TError>:IResult<TResult,TError>
{
public TError ErrorValue {get;}

public Error(TError error) { ErrorValue=error;}

public void Deconstruct(out TError error) { error=ErrorValue;}
}

在那种情况下,表达式可以写成:

return data switch {    
Error<int,string> e => e,
Success<int,string> (var result) => new Success<int,string>(result*3),
_ => throw new Exception("Unexpected type!")
};

为空性

问题从可空引用类型开始,那么可空性呢?如果我们尝试传递 null,我们会在 C# 8 中收到警告吗?

是的,只要启用了 NRT。这段代码:

#nullable enable

void Main()
{
IResult<string,string> data=new Success<string,string>(null);
var it=Append1(data);
Console.WriteLine(it);
}

IResult<string,string> Append1(IResult<string,string> data)
{
return data switch { Error<string,string> e=>e,
Success<string,string> (var result)=>
new Success<string,string>(result+"1"),
_ => throw new Exception("Unexpected type!")
};
}

生成 CS8625: Cannot convert null literal to non-nullable reference type

尝试

string? s=null;
IResult<string,string> data=new Success<string,string>(s);

生成 CS8604: Possible null reference argument ....

关于c# - 可空引用类型和 Either 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58076171/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com