Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the right way to check for inheritance from a class/interface?

The code below is looping through a dictionary of strings and IMyCompanySettings looking for values that implement IMyCompanyProductSetting. Clearly, trying to cast and raising an exception is a very expensive way to do this.

    public static List<IMyCompanyProductSetting> GetProductSettings(ConfigurationManager cfm)
    {
        List<IMyCompanyProductSetting> ret = new List<IMyCompanyProductSetting>();
        foreach(IMyCompanySetting setting in cfm.Values)
        {
            try
            {
                IMyCompanyProductSetting prod = (IMyCompanyProductSetting)setting;
                ret.Add(prod);

            }
            catch
            {
              // Do nothing.
            }
        }
        return ret;
    }

What's a better way to do this?

like image 797
Yes - that Jake. Avatar asked Nov 28 '22 05:11

Yes - that Jake.


2 Answers

Casting 101 [general info on casting stuff]:

Use [object] is [interface/class] expression:

if (setting is IMyCompanyProductSetting) {
  ...
}

Alternatively you can use the as keyword which tries to cast the object and if it fails, instead of throwing exception, it'll return null. Note that the target type must be a reference type in the as keyword:

var prod = setting as IMyCompanyProductSetting; 

if (prod != null) {
   ...
}

You should always use the above code instead of the equivalent exception handling.

Filtering an IEnumerable by type (LINQy):

As Jon Skeet pointed out, you should use OfType extension method to filter a sequence easily (assuming you got LINQ):

var filteredSequence = sequence.OfType<TargetType>();

Casting an IEnumerable to type (LINQy):

If you want to try casting each element to the target type (as opposed to filtering by type), you can use the Cast extension method:

var castedSequence = sequence.Cast<TargetType>();
like image 200
Trevor Dixon Avatar answered Nov 30 '22 19:11

Trevor Dixon


The "hard" way (pre-LINQ) is to use "as". This is more efficient than using "is" and then casting each time (as both the "is" and the cast require execution-time checks):

IMyCompanyProductSetting prod = setting as IMyCompanyProductSetting;
if (prod != null)
{
    ret.Add(prod);
}

See another question for when to use "as" and when to use a cast.

If you're using .NET 3.5, however, it's really easy:

return cfm.Values.OfType<IMyCompanyProductSetting>().ToList();

Very easy :)

like image 42
Jon Skeet Avatar answered Nov 30 '22 20:11

Jon Skeet