Method for template: "if (obj is Abc && (obj as Abc) ...)"
There are two simple classes here:
class Abc { public int x; }
class Bcd { public int y; }
Given what obj
a type has object
, here are some test examples for Abc
or Bcd
with specific characteristics:
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);
What a good way to deal with this pattern:
if (obj is Abc && (obj as Abc).SomePropertyOrMethod && ...
One approach is the extension method Is
:
public static bool Is<T>(this object obj, Func<T, bool> pred) where T : class
=> (obj is T) && pred(obj as T);
That being said, the above examples can be written as:
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);
Thus, the expressions are (obj as ...)
not repeated.
Are there other approaches to this pattern?
This pattern matching clause seems like it will handle it well (see section 8.1).
source to share
I feel like it takes a simple thing and complicates it. Also, the namespace pollution caused by the extension object
is not very nice. Also, this is a misuse as
. It should be a cast toss (for example ((Abc)obj)
) because we expect the cast to always succeed. Cast cast has validation and is a good exception for this built-in. He documents the fact that this is expected to be successful.
An alternative could be to declare a variable:
var abc = obj as Abc;
if (abc != null && abc.x > 0 && Math.Pow(abc.x, 2) > 100)
Console.WriteLine(123);
Seems simple enough. I don't see any problem with this.
However, the extension method approach can be useful in places where you cannot easily declare a variable, such as in certain queries or in deeply nested expressions. This is usually undesirable, but sometimes it happens.
source to share
I'm not sure which is the best / worst, but (obj as Abc).x
may end up in NullReferenceException
if the failure occurs. One way I can see is to reverse the status check as shown below:
Abc a = obj as Abc;
if (a != null && a.x > 0 && Math.Pow(a.x, 2) > 100)
Console.WriteLine(123);
Thus, there is no need to check the condition obj is Abc
, since it a != null
will true
only happen when the obj as Abc
casting has time.
source to share