c# 使用模式匹配以及 is 和 as 运算符安全地进行强制转换
作者:olprod 发布时间:2022-11-23 09:47:51
由于是多态对象,基类类型的变量可以保存派生类型。 要访问派生类型的实例成员,必须将值强制转换 * 生类型。 但是,强制转换会引发 InvalidCastException 风险。 C# 提供模式匹配语句,该语句只有在成功时才会有条件地执行强制转换。 C# 还提供 is 和 as 运算符来测试值是否属于特定类型。
下面的示例演示如何使用模式匹配 is 语句:
class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Mammal : Animal { }
class Giraffe : Mammal { }
class SuperNova { }
class Program
{
static void Main(string[] args)
{
var g = new Giraffe();
var a = new Animal();
FeedMammals(g);
FeedMammals(a);
// Output:
// Eating.
// Animal is not a Mammal
SuperNova sn = new SuperNova();
TestForMammals(g);
TestForMammals(sn);
// Output:
// I am an animal.
// SuperNova is not a Mammal
}
static void FeedMammals(Animal a)
{
if (a is Mammal m)
{
m.Eat();
}
else
{
// variable 'm' is not in scope here, and can't be used.
Console.WriteLine($"{a.GetType().Name} is not a Mammal");
}
}
static void TestForMammals(object o)
{
// You also can use the as operator and test for null
// before referencing the variable.
var m = o as Mammal;
if (m != null)
{
Console.WriteLine(m.ToString());
}
else
{
Console.WriteLine($"{o.GetType().Name} is not a Mammal");
}
}
}
前面的示例演示了模式匹配语法的一些功能。 if (a is Mammal m) 语句将测试与初始化赋值相结合。 只有在测试成功时才会进行赋值。 变量 m 仅在已赋值的嵌入式 if 语句的范围内。 以后无法在同一方法中访问 m。 前面的示例还演示了如何使用 as 运算符将对象转换为指定类型。
也可以使用同一语法来测试可为 null 的值类型是否具有值,如以下示例所示:
class Program
{
static void Main(string[] args)
{
int i = 5;
PatternMatchingNullable(i);
int? j = null;
PatternMatchingNullable(j);
double d = 9.78654;
PatternMatchingNullable(d);
PatternMatchingSwitch(i);
PatternMatchingSwitch(j);
PatternMatchingSwitch(d);
}
static void PatternMatchingNullable(System.ValueType val)
{
if (val is int j) // Nullable types are not allowed in patterns
{
Console.WriteLine(j);
}
else if (val is null) // If val is a nullable type with no value, this expression is true
{
Console.WriteLine("val is a nullable type with the null value");
}
else
{
Console.WriteLine("Could not convert " + val.ToString());
}
}
static void PatternMatchingSwitch(System.ValueType val)
{
switch (val)
{
case int number:
Console.WriteLine(number);
break;
case long number:
Console.WriteLine(number);
break;
case decimal number:
Console.WriteLine(number);
break;
case float number:
Console.WriteLine(number);
break;
case double number:
Console.WriteLine(number);
break;
case null:
Console.WriteLine("val is a nullable type with the null value");
break;
default:
Console.WriteLine("Could not convert " + val.ToString());
break;
}
}
}
前面的示例演示了模式匹配用于转换的其他功能。 可以通过专门检查 null 值来测试 NULL 模式的变量。 当变量的运行时值为 null 时,用于检查类型的 is 语句始终返回 false。 模式匹配 is 语句不允许可以为 null 值的类型,如 int? 或 Nullable<int>,但你可以测试任何其他值类型。 上述示例中的 is 模式不局限于可为空的值类型。 也可以使用这些模式测试引用类型的变量具有值还是为 null。
前面的示例还演示如何在变量为其他类型的 switch 语句中使用类型模式。
如果需要测试变量是否为给定类型,但不将其分配给新变量,则可以对引用类型和可以为 null 的值类型使用 is 和 as 运算符。 以下代码演示如何在引入模式匹配以测试变量是否为给定类型前,使用 C# 语言中的 is 和 as 语句:
class Animal
{
public void Eat() { Console.WriteLine("Eating."); }
public override string ToString()
{
return "I am an animal.";
}
}
class Mammal : Animal { }
class Giraffe : Mammal { }
class SuperNova { }
class Program
{
static void Main(string[] args)
{
// Use the is operator to verify the type.
// before performing a cast.
Giraffe g = new Giraffe();
UseIsOperator(g);
// Use the as operator and test for null
// before referencing the variable.
UseAsOperator(g);
// Use the as operator to test
// an incompatible type.
SuperNova sn = new SuperNova();
UseAsOperator(sn);
// Use the as operator with a value type.
// Note the implicit conversion to int? in
// the method body.
int i = 5;
UseAsWithNullable(i);
double d = 9.78654;
UseAsWithNullable(d);
}
static void UseIsOperator(Animal a)
{
if (a is Mammal)
{
Mammal m = (Mammal)a;
m.Eat();
}
}
static void UsePatternMatchingIs(Animal a)
{
if (a is Mammal m)
{
m.Eat();
}
}
static void UseAsOperator(object o)
{
Mammal m = o as Mammal;
if (m != null)
{
Console.WriteLine(m.ToString());
}
else
{
Console.WriteLine($"{o.GetType().Name} is not a Mammal");
}
}
static void UseAsWithNullable(System.ValueType val)
{
int? j = val as int?;
if (j != null)
{
Console.WriteLine(j);
}
else
{
Console.WriteLine("Could not convert " + val.ToString());
}
}
}
正如你所看到的,将此代码与模式匹配代码进行比较,模式匹配语法通过在单个语句中结合测试和赋值来提供更强大的功能。 尽量使用模式匹配语法。
来源:https://github.com/dotnet/docs.zh-cn/blob/live/docs/csharp/how-to/safely-cast-using-pattern-matching-is-and-as-operators.md


猜你喜欢
- 1. 为什么需要智能指针?简单的说,智能指针是为了实现类似于Java中的垃圾回收机制。Java的垃圾回收机制使程序员从繁杂的内存管理任务中彻
- <customErrors>节点用于定义一些自定义错误信息的信息。此节点有Mode和defaultRedirect两个属性,其中
- Android开发过程中,经常遇到一个项目需要重复的定义相同样式的标题栏,Android相继推出了actionBar, toolBar, 相
- 实践过程效果代码public partial class Frm_Libretto : Form{ public
- 一、引言在许多编程语言中,都有函数回调这一概念。C 和 C++ 中有函数指针,因此可以将函数作为参数传给其它函数,以便过后调用。而在 Jav
- 之前从他人的博文,还有一些书籍中了解到 常量是放在常量池 中,细节的内容无从得知,总觉得面前的东西是一个几乎完全的黑盒,总是觉得不舒服,于是
- 前言本文详细介绍如何使用spring-boot2.x快速整合log4j2日志框架。spring-boot2.x使用logback作为默认日志
- GlobalLock的作用对于某条数据进行更新操作,如果全局事务正在进行,当某个本地事务需要更新该数据时,需要使用@GlobalLock确保
- 在.Net下DateTime.Ticks获得的是个long型的时间整数,具体表示是至0001 年 1 月 1 日午夜 12:00:00 以来
- 这几天看了下之前写的有关微信支付的博客,看的人还是挺多的,看了下留言不知道是因为博客写的不够细还是什么情况,大多都找我要源码,我觉得吧程序员
- idea去掉不想commit的文件我们项目在每次commit代码时,有时候会有一些不想提交又不能删除的代码,怎么做呢?此方法亲测最方便!!!
- 在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。为什么选择 Kotlin? 简洁:
- 之前有简单介绍过java多线程的使用,已经Thread类和Runnable类,为了更好地理解多线程,本文就Thread进行详细的分析。sta
- 本文介绍MediaPlayer的使用。MediaPlayer可以播放音频和视频,另外也可以通过VideoView来播放视频,虽然VideoV
- 本文实例为大家分享了Android实现全局悬浮框的具体代码,供大家参考,具体内容如下效果图:代码实现:Androidmanifest.xml
- SpringCloud启动失败问题Nacos配置读取失败org.yaml.snakeyaml.error.YAMLException: ja
- 网上找了几个,写的都不太适合,有的写出来了,也没有给出参考的算法链接。这样就导致了如果产生错误我们无法排查(不懂原理怎么排查对吧)。如果在使
- 前言Vector是java.util包中的一个类。 SynchronizedList是java.util.Collections中的一个静态
- 在派生类中引发基类事件以下简单示例演示了在基类中声明可从派生类引发的事件的标准方法。此模式广泛应用于 .NET Framework 类库中的
- Java File类 mkdir 不能创建多层目录File f = new File("/home/jp/Upload"