Можно также проверить реализацию интерфейса с помощью ключевого слова is. Если соответствующий объект не совместим указанным интерфейсом, будет возвращено значение false. А если тип совместим с интерфейсом, вы можете смело вызвать его члены без использования логики try/catch.
Для примера предположим, что мы изменили массив типов Shape так, что теперь некоторые его члены реализуют IPointy. Вот как с помощью ключевого слова is можно выяснить, какие из элементов в массиве поддерживают этот интерфейс.
static void Main(string[] args) {
…
Shape[] s = {new Hexagon, new Circle, new Triangle("Joe"), new Circle("JoJo")};
for (int i = 0; i ‹ s.Length; i++) {
//
Напомним, что базовый класс Shape определяет абстрактный
// член Draw, поэтому все формы могут отображать себя.
s[i].Draw
// Кто с вершинами?
if (s[i] is IPointy) Console.WriteLine("-› Вершин: {0} ", ((IPointy)s[i]).Points);
else Console.WriteLine("-› {0} без вершин!", s[i].PetName);
Поскольку интерфейсы являются полноценными типами .NET, вы можете конструировать методы, которые будут использовать интерфейсы, как параметры. Для примера предположим, что мы определили другой интерфейс с именем IDraw3D.
// Моделируем возможность отображения типа в пространстве.
public interface IDraw3D {
void Draw3D;
}
Предположим также, что две из наших трех форм (Circle и Hexagon) сконфигурированы для поддержки этого нового поведения.
// Circle поддерживает IDraw3D.
public class Circle: Shape, IDraw3D {
…
public void Draw3D {
Console.WriteLine("3D-отображение окружности!");
}
}
// Hexagon поддерживает IPointy и IDraw3D.
public class Hexagon: Shape, IPointy, IDraw3D {
…
public void Draw3D { Console.WriteLine ("3D-отображение шестиугольника!"); }
}
На рис. 7.3 показана соответствующая обновленная диаграмма классов, полученная в Visual Studio 2005.
Рис. 7.3. Обновленная иерархия форм
Если
определить метод, использующий интерфейс IDraw3D в виде параметра, вы получите возможность передать любой объект, реализующий IDraw3D (но если вы попытаетесь передать тип, не поддерживающий нужный интерфейс, будет сгенерирована ошибка компиляции). Рассмотрим следующий фрагмент программного кода.
// Создание нескольких форм.
// Если это возможно, их отображение в трехмерном виде.
Shape [] s = {new Hexagon, new Circle, new Triangle("Joe"), new Circle("JoJo")};
for (int i = 0; i ‹ s.Length; i++) {
…
// Можно ли отобразить в 3D-виде?
if (s[i] is IDraw3D) DrawIn3D((IDraw3D)s[i]);
}
}
}
Обратите внимание на то, "что треугольник не отображается, поскольку он не является IDraw3D-совместимым (рис. 7.4).
Рис.7.4. Интерфейсы в качестве параметров
Интерфейсы в качестве возвращаемых значений
Интерфейсы можно использовать и в качестве возвращаемых значений методов. Например, можно создать метод, который берет любой System.Object, проверяет на совместимость с IPointy и возвращает ссылку на извлеченный интерфейс.
// Этот метод проверяет соответствие IPointy и, если это возможно,
// возвращает ссылку на интерфейс.
static IPointy ExtractPointyness(object o) {
if (o is IPointy) return (IPointy)o;
else return null;
}
С этим методом можно взаимодействовать так, как предлагается ниже.
static void Main(string[] args) {
// Попытка извлечь IPointy из объекта Car.
Car myCar = new Car;
IPointy itfPt = ExtractPointyness(myCar);
if (itfPt!= null) Console.WriteLine("Объект имеет {0} вершин.", itfPt.Points);
else Console.WriteLine("Этот объект не реализует IPointy");