Безопасный и простой доступ к явным членам интерфейса в C # - PullRequest
0 голосов
/ 20 мая 2010

Когда я работаю с явными реализациями интерфейса в C #, часто возникает необходимость привести объект к одному из его интерфейсов, чтобы получить доступ к члену этого интерфейса.Из-за повышенной надежности и удобства обслуживания, обеспечиваемой проверкой типов во время компиляции, я всегда предпочитал использовать неявные преобразования для выполнения этого.Единственный известный мне способ сделать это - задействовать две строки кода и ввести еще одну переменную в область видимости.Ниже приведен пример:

public interface IMyType
{
    string SayHello();
}

public class MyType : IMyType
{
    string IMyType.SayHello() { return "Hello!"; }
}

class Program
{
    static void Main(string[] args)
    {
        var item = new MyType();

        // Option 1 - Implicit cast. Compile time checked but takes two lines.
        IMyType item2 = item;
        System.Console.WriteLine(item2.SayHello());

        // Option 2 - One line but risks an InvalidCastException at runtime if MyType changes.
        System.Console.WriteLine(((IMyType)item).SayHello());

        // Option 3 - One line but risks a NullReferenceException at runtime if MyType changes.
        System.Console.WriteLine((item as IMyType).SayHello());
    }
}

Поскольку компилятор знает , что MyType реализует IMyType Я предполагаю, что неявное приведение лучше, чем явное приведение, поскольку последующее изменение вобъявление MyType приведет к ошибке компиляции вместо InvalidCastException во время выполнения.Однако я несколько предпочитаю простоту явного синтаксиса приведения и часто вижу, что он используется в коде других людей.

Мой вопрос состоит из трех частей:

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

Ответы [ 4 ]

2 голосов
/ 20 мая 2010

Вот один из лайнеров, проверенных во время компиляции:

public static class Converter
{
    public static T ReturnAs<T>(T item)
    {
        return item;
    }
}


class Program
{
    static void Main(string[] args)
    {
        var item = new MyType();

        // Option 1 - Implicit cast. Compile time checked but takes two lines.
        IMyType item2 = item;
        System.Console.WriteLine(item2.SayHello());

        // Option 2 - One line but risks an InvalidCastException at runtime if MyType changes.
        System.Console.WriteLine(((IMyType)item).SayHello());

        // Option 3 - One line but risks a NullReferenceException at runtime if MyType changes.
        System.Console.WriteLine((item as IMyType).SayHello());

        // Option 4 - compile time one liner
        Converter.ReturnAs<IMyType>(item).SayHello();
    }
}
1 голос
/ 20 мая 2010

В качестве ответа на все три вопроса: полагайтесь на неявные приведения как общее правило. Вы программируете с интерфейсом, а не с реализацией.

Что касается последнего, если вы действительно должны полагаться на программирование с использованием реализации (определенного производного класса), то убедитесь, что объект может быть приведен к типу, прежде чем пытаться что-либо с ним делать. Примерно так:

var IMyType item3 = item as MyConcreteType;
if(item3 != null) {
    item3.SayHello();
}
0 голосов
/ 20 мая 2010

Если вы не уверены, что объект является экземпляром интерфейса, выполните проверку as / null. Обычно вы возвращаете интерфейс из вызова метода / функции, и в этом случае вы просто сохраняете его в переменной без преобразования (хотя проверка нуля все еще может быть необходима).

0 голосов
/ 20 мая 2010

Мне обычно нравится это как:

class Program
{
    static void Main(string[] args)
    {
        var item = new MyType();
        if( item is IMyType ){
          Console.WriteLine( (item as IMyType).SayHello() );
        }
        else { /* Do something here... */ }

     }
}
...