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).

+3


source to share


3 answers


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.

+5


source


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.

+3


source


Add some static check:

public static bool Is<T, TBase>(this TBase obj, Func<T, bool> pred)
    where TBase : class
    where T : class, TBase
{
    var t = obj as T;
    return t != null && pred(t);
}

      

Use this:

TypeBase obj;
...
if (obj.Is((TypeA obj) => ...))

      

0


source







All Articles