Доступ к методам интерфейса без обращения к классу

Скажем, у меня есть такой интерфейс в проекте под названием "Интерфейс":

public interface TestInterface
{
    string Operation();
}

и класс, который реализует это. Этот класс находится в другом проекте "Класс":

public class TestClass : TestInterface
{
    public TestClass() { }

    public string Operation()
    {
        return "This is an Operation";
    }
}

Мой клиент делает что-то вроде этого (что опять-таки в другом проекте "Клиент"):

class Program
{
    static void Main(string[] args)
    {
        TestInterface i = new TestClass();
        i.Operation();
    }
}

Мой вопрос связан с этой строкой:

TestInterface i = new TestClass();

Добавив эту строку, я фактически вынужден добавить ссылки как на "Интерфейс", так и на "Класс" проектов из моего "Клиентского" проекта. Так зачем все это суетиться? Разве я не могу напрямую ссылаться на "Класс", не оставляя "Интерфейс" между ними? Есть ли способ получить доступ к методам только через интерфейс (без ссылки на класс реализации)? Я что-то здесь упускаю?

5 ответов

Есть ли способ получить доступ к методам только через интерфейс

Да, есть. Вы можете динамически загрузить сборку с TestClass не ссылаясь на него, создайте его экземпляр с помощью Activator.CreateInstance и приведите его к типу интерфейса:

var assembly = Assembly.Load(...);
var typeFromAssembly = assembly.GetTypes()...;
var myInterfaceVar = (TestInterface)Activator.CreateInstance(typeFromAssembly);

... или... вы можете использовать одну из существующих DI-платформ (например, MEF) и делать то же самое более правильным образом:

[Import]
private TestInterface myInterfaceField;

или же:

var myInterfaceVar = compositionContainer.GetExportedValue<TestInterface>();

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

Сделать ваш код полностью независимым от реализации TestInterface использовать инверсию зависимости. Этого можно достичь с помощью некоторой структуры внедрения зависимостей.

Например, с Unity вы можете настроить реализацию через XML

<register type="TestInterface" 
          mapTo="Foo.Bar.TestClass, Foo.Bar" />

И ваш код будет зависеть только от Unity (без ссылок на реализацию):

TestInterface i = Container.Resolve<TestInterface>();

В этом конкретном примере нет никаких преимуществ.

Но представьте метод:

public void Foo(ITestInterface handler)
{
    handler.Operation();
}

Сейчас, Foo работает только на интерфейсе, и ему все равно, какой конкретный класс реализует этот интерфейс. Теперь вы можете позвонить Foo с экземпляром TestClass или с TestClass2, который может быть определен в другой сборке.

У вас есть интерфейс, так что ваше приложение может иметь plug in's..

Таким образом, вы делите свой интерфейсный dll с любым, кто хочет создать приложение-плагин для вашего приложения, а затем вы можете привести этот новый класс плагинов к интерфейсу и вызвать методы для него.

Если вы не приведете класс к интерфейсу, как же вы собираетесь заставить класс плагина работать для вашего приложения?

Вы можете достичь поведения, которое вы описали, используя МОК. Unity - это контейнер внедрения зависимостей, который позволяет создавать экземпляры, не создавая экземпляры вручную.

Например, если бы вы зарегистрировали свой класс и интерфейс на единицу, вы бы напрямую использовали интерфейс;

TestInterface i = Container.Resolve<TestInterface>();
Другие вопросы по тегам