Как правильно проверить наследование от класса / интерфейса? - PullRequest
4 голосов
/ 03 апреля 2009

Приведенный ниже код просматривает словарь строк и IMyCompanySettings ищет значения, которые реализуют IMyCompanyProductSetting . Очевидно, что попытка разыграть и вызвать исключение - очень дорогой способ сделать это.

    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;
    }

Какой лучший способ сделать это?

Ответы [ 5 ]

14 голосов
/ 03 апреля 2009

Casting 101 [общая информация о кастинге]:

Использовать [object] is [interface/class] выражение:

if (setting is IMyCompanyProductSetting) {
  ...
}

В качестве альтернативы вы можете использовать ключевое слово as, которое пытается привести объект к объекту, и, если он потерпит неудачу, вместо выдачи исключения он вернет null. Обратите внимание, что целевой тип должен быть ссылочным типом в ключевом слове as:

var prod = setting as IMyCompanyProductSetting; 

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

Вы должны всегда использовать приведенный выше код вместо эквивалентной обработки исключений.

Фильтрация IEnumerable по типу (LINQy):

Как отметил Джон Скит, вы должны использовать OfType метод расширения, чтобы легко фильтровать последовательность (при условии, что вы получили LINQ):

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

Приведение IEnumerable к типу (LINQy):

Если вы хотите попробовать привести каждый элемент к целевому типу (в отличие от фильтрации по типу), вы можете использовать метод расширения Cast:

var castedSequence = sequence.Cast<TargetType>();
7 голосов
/ 03 апреля 2009

«Жестким» способом (pre-LINQ) является использование «как». Это более эффективно, чем использование «is» и последующее приведение к типу (так как «is» и приведение требуют проверки времени выполнения):

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

См. другой вопрос о том, когда использовать «как» и когда использовать приведение.

Однако, если вы используете .NET 3.5, это действительно просто:

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

Очень просто:)

2 голосов
/ 03 апреля 2009

Мехрдад имеет ответ. Я только добавлю, что вы никогда не должны использовать этот трюк "попробуй / поймай все". В лучшем случае в этом случае вы пытаетесь поймать InvalidCastException. Вы не хотели бы игнорировать какое-то другое исключение, возможно, из-за выполнения метода, который вы пытаетесь вызвать.

1 голос
/ 03 апреля 2009

Либо сделать

if (setting is IMyCompanyProductSetting)
{
  IMyCompanyProductSetting prod = (IMyCompanyProductSetting)setting;
}

или

IMyCompanyProductSetting prod = setting as IMyCompanyProductSetting;
if (setting != null)
{
}
1 голос
/ 03 апреля 2009

Вместо этого вы должны использовать оператор «Is» для более краткого и менее подверженного ошибкам кода. Смотрите пример ниже.

 if (setting Is IMyCompanyProductSetting)
  ret.add((IMyCompanyProductSetting)setting);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...