这是两个简单的类:
class Abc { public int x; }
class Bcd { public int y; }
Run Code Online (Sandbox Code Playgroud)
鉴于它obj
是类型object
,这里有几个测试Abc
或Bcd
具有某些特征的例子:
if (obj is Abc && (obj as Abc).x > 0 && Math.Pow((obj as Abc).x, 2) > 100)
Console.WriteLine(123);
if (obj is Bcd && (obj as Bcd).y > 0 && Math.Pow((obj as Bcd).y, 2) > 100)
Console.WriteLine(234);
Run Code Online (Sandbox Code Playgroud)
处理这种模式的好方法是什么:
if (obj is Abc && (obj as Abc).SomePropertyOrMethod && ...
Run Code Online (Sandbox Code Playgroud)
一种方法是Is
扩展方法:
public static bool Is<T>(this object obj, Func<T, bool> pred) where T : class
=> (obj is T) && pred(obj as T);
Run Code Online (Sandbox Code Playgroud)
有了这个,上面的例子可以写成:
if (obj.Is<Abc>(abc => abc.x > 0 && Math.Pow(abc.x, 2) > 100))
Console.WriteLine(123);
if (obj.Is<Bcd>(bcd => bcd.y > 0 && Math.Pow(bcd.y, 2) > 100))
Console.WriteLine(234);
Run Code Online (Sandbox Code Playgroud)
这样(obj as ...)
就不再重复表达了.
这种模式还有其他方法吗?
这种模式匹配提议似乎可以很好地处理这个问题(参见第8.1节).
我觉得这需要一件简单的事情并使其变得复杂.此外,扩展导致的名称空间污染object
也不是很好.此外,这是滥用as
.这应该是投掷演员(例如((Abc)obj)
),因为我们期望演员总是成功.投掷演员有一个断言和内置的一个很好的例外.它正在记录这一预期会成功的事实.
另一种方法是声明一个变量:
var abc = obj as Abc;
if (abc != null && abc.x > 0 && Math.Pow(abc.x, 2) > 100)
Console.WriteLine(123);
Run Code Online (Sandbox Code Playgroud)
看起来很简单.我认为没有问题.
也就是说,扩展方法方法在您无法轻松声明变量的地方非常有用,例如在某些查询或深层嵌套表达式中.这通常是不受欢迎的,但有时会发生.