C#是否有类似的value_or_execute或value_or_throw功能?

huangapple go评论76阅读模式
英文:

Does C# have some kind of value_or_execute or value_or_throw?

问题

我正在学习C#,尝试处理“a可能为null”的警告。

我想知道,因为当某些东西为空时,通常会出错,要么通过从函数返回,要么抛出异常,C#是否有某种用于这种情况的语法糖?

我心目中的示例是:int a = obtainA() ??? { Console.WriteLine("致命错误;") return };(这不是真正的代码)

我知道????=运算符,但它们似乎在这里没有太多帮助,我也没有找到更好的方法。

如果没有,那么最接近模拟这种情况的方法是什么?有没有比编写以下代码更好的方法?

int? nullableA = obtainA();
int a;
if (nullableA.HasValue) {
    a = nullableA.Value;
}
else {
    Console.WriteLine("致命错误");
    return;
}
/* 使用a,或者跳过定义a并信任静态分析器注意到nullableA不为null */
英文:

I'm learning C# and trying to handle the influx of "a could be null" warnings.

I was wondering, since it's such a common case to error out when something is null, either by returning from the function or throwing an exception, does C# have some kind of syntactical sugar for that case ?

Example of what I have in mind: int a = obtainA() ??? { Console.WriteLine("Fatal error;") return }; (this is not real code)

I know about the ?? and ??= operators, but they don't seem to help much here and I haven't found better.

If not, what would be the closest we have to emulating this ? Is there no better way than to write the following ?

int? nullableA = obtainA();
int a;
if (nullableA.HasValue) {
    a = nullableA.Value;
}
else {
    Console.WriteLine("Fatal error");
    return;
}
/* use a, or skip defining a and trust the static analyzer to notice nullableA is not null */

答案1

得分: 6

"or_throw" 可以在 C# 7 及以后版本中使用 ?? 运算符实现,使用了该语言版本中引入的 throw 表达式

int? i = null;
int j = i ?? throw new Exception();

另一种抛出异常的方法是使用 ArgumentNullException.ThrowIfNull

#nullable enable
int? i = null;
ArgumentNullException.ThrowIfNull(i);
int j = i.Value; // 没有警告,编译器确定 i 在这里不可能为 null

您还可以编写自己的支持可空流分析的方法(就像 ArgumentNullException.ThrowIfNull 一样),使用 C# 编译器解释的用于空状态静态分析的属性

#nullable enable
int? i = null;
if (IsNullAndReport(i)) return;
int j = i.Value; // 没有警告,编译器确定 i 在这里不可能为 null

bool IsNullAndReport([NotNullWhen(false)]int? v, [CallerArgumentExpression(nameof(i))] string name = "")
{
	if (v is null)
	{
		Console.WriteLine($"{name} is null;");
		return true;
	}

	return false;
}

还有模式匹配的方法:

int? i = null;
if (i is { } j) // 检查 i 不为 null 并将值分配给局部变量 j
{
	// 使用 j,它是 int 类型
}
else
{
	Console.WriteLine("致命错误");
	return;
}
英文:

"or_throw" can be achieved with ?? operator since C# 7 using the throw expressions introduced in this language version:

int? i = null;
int j = i ?? throw new Exception();

Another throw approach can be achieved with ArgumentNullException.ThrowIfNull:

#nullable enable
int? i = null;
ArgumentNullException.ThrowIfNull(i);
int j = i.Value; // no warning, compiler determines that i can't be null here

Also you can write your own method supporting nullable flow analysis (like ArgumentNullException.ThrowIfNull does) with attributes for null-state static analysis interpreted by the C# compiler:

#nullable enable
int? i = null;
if (IsNullAndReport(i)) return;
int j = i.Value; // no warning, compiler determines that i can't be null here

bool IsNullAndReport([NotNullWhen(false)]int? v, [CallerArgumentExpression(nameof(i))] string name = "")
{
	if (v is null)
	{
		Console.WriteLine($"{name} is null;");
		return true;
	}

	return false;
}

And pattern matching approach:

int? i = null;
if (i is { } j) // checks if i is not null and assigns value to scoped variable 
{
	// use j which is int
}
else
{
	Console.WriteLine("Fatal error");
	return;
}

答案2

得分: 2

`??`运算符通常用于这种情况,特别是在参数为空检查中:

```csharp
public class A
{
   private readonly string _firstArg;
   private readonly string _secondArg;
   public A(string firstArg, string secondArg)
   {
      _firstArg = firstArg ?? throw new ArgumentNullException(nameof(firstArg));
      _secondArg = secondArg ?? throw new ArgumentNullException(nameof(secondArg));
   }
}

如果传递的参数为null,这会引发异常,确保字段值永远不会为null(因此不需要在类的其他任何地方进行进一步的null检查)。


<details>
<summary>英文:</summary>

The `??` operator is often used for this, particularly in parameter null tests:

```csharp

public class A
{
   private readonly string _firstArg;
   private readonly string _secondArg;
   public A(string firstArg, string secondArg)
   {
      _firstArg = firstArg ?? throw new ArgumentNullException(nameof(firstArg));
      _secondArg = secondArg ?? throw new ArgumentNullException(nameof(secondArg));
   }
}

This throws an exception if the passed parameter was null, ensuring that the field values will never be null (and thus not requiring any further null tests anywhere else in the class).

答案3

得分: 1

这也有一个用于此的静态辅助方法:ArgumentNullException.ThrowIfNull():

int? nullableA = null;
ArgumentNullException.ThrowIfNull(nullableA);

这将抛出:

> ArgumentNullException: 值不能为 null。 (参数 'nullableA')

它使用新的 CallerArgumentExpressionAttribute 自动将相关变量的名称添加到错误消息中。

英文:

There is also a static helper method for this: ArgumentNullException.ThrowIfNull():

int? nullableA = null;
ArgumentNullException.ThrowIfNull(nullableA);

This will throw:

> ArgumentNullException: Value cannot be null. (Parameter 'nullableA')

It uses the new CallerArgumentExpressionAttribute to auto-magically add the name of the variable in question to the error message.

huangapple
  • 本文由 发表于 2023年1月9日 17:18:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75055180.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定