Особенности реализации интерфейсов

Неявная реализация

Неявный способ аналогичен способу реализации интерфейсов в C++ и заключается в простой реализации в классе или структуре методов с совпадающей сигнатурой методов интерфейса.

При реализации интерфейса в структуре должны быть реализованы все методы наследованных интерфейсов. В случае реализации интерфейсов в классе, реализация части (или всех) методов  может быть заменена декларацией абстрактных методов.

Неявная реализация

Явная реализация используется при реализации интерфейсов, содержащих функции с одинаковыми именами и сигнатурами и заключающаяся в указании полного имени метода, например object IConeable.Clone().

Данный способ — явное указание компилятору, метод какого именно интерфейса реализуется. Именно поэтому (я предполагаю) данный способ и назвали явной реализацией. При явной реализации интерфейса все методы интерфейса реализуются как виртуальные и закрытые.

Реализация интерфейса ICloneable


public struct Cloneable : ICloneable
{
	private Cloneable(Cloneable copy)
	{
	}
		
	// .method public hidebysig instance valuetype Interfaces.Cloneable 
	// Clone() cil managed
	public Cloneable Clone()
	{
		return new Cloneable(this);
	}
	
	// .method private hidebysig newslot virtual final 
// instance object  System.ICloneable.Clone() cil managed
	object ICloneable.Clone()
	{
		return new Cloneable(this);
	}
}

В структуре объявлены два метода с одинаковым именем Clone. Метод Clone объекта, возвращает объект типа Cloneable (размерный тип). Данный метод не виртуальный. Явно реализованный метод Clone интерфейса Icloneable, возвращает интерфейс, виртуальный, и закрытый.

Данный метод реализации следует использовать с осторожностью, так как это влечет за собой определенные неудобства в использовании:

Реализация свойств

Если в интерфейсе декларировано свойство с одним методом, например get, при реализации данного интерфейса свойство можно дополнить методом set. Т.е. декларация свойства не накладывает ограничений на то, как именно оно должно быть реализовано.

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

namespace Lib
{
	public interface INamed
	{
		string Name { get; }
	}

	internal class Implementation : INamed
	{
		private string _name;
		public Implementation(string name)
		{
			_name = name;
		}

		public string Name
		{
			get { return _name; }
			set { _name = value; }
		}
	}

	public static class API
	{
		public static INamed GetNamed()
		{
			return new Implementation("test");
		}
	}
}