Как определить реализацию интерфейса по умолчанию в С#?
В С# есть код черной магии, где вы можете определить реализацию интерфейса по умолчанию.
Итак, вы можете написать
var instance = new ISomeInterface();
Любые указатели?
ОБНОВЛЕНИЕ 1: Обратите внимание, что это не спросит, является ли это хорошей идеей. Как это было возможно?
ОБНОВЛЕНИЕ 2: любому, кто видит принятый ответ.
- "к этому нужно относиться просто как к любопытству". от Марка Гравеля "Новинг вверх" Интерфейсы
- "Неплохая идея использовать инструмент, предназначенный для взаимодействия с COM, чтобы сделать что-то совершенно и совершенно другое. Это делает ваш код невозможным для понимания для следующего парня, который должен его поддерживать" от Eric Lippert "Newing up" Интерфейсы
- "Хотя это может сработать, если оно было когда-либо обнаружено в производственном коде с помощью рационального кодера, вместо этого было бы реорганизовано использование базового класса или инъекции зависимостей". от Стивена Клири в комментарии ниже.
Ответы
Ответ 1
Вот черная магия:
class Program
{
static void Main()
{
IFoo foo = new IFoo("black magic");
foo.Bar();
}
}
[ComImport]
[Guid("C8AEBD72-8CAF-43B0-8507-FAB55C937E8A")]
[CoClass(typeof(FooImpl))]
public interface IFoo
{
void Bar();
}
public class FooImpl : IFoo
{
private readonly string _text;
public FooImpl(string text)
{
_text = text;
}
public void Bar()
{
Console.WriteLine(_text);
}
}
Обратите внимание, что вы можете не только создать экземпляр интерфейса, но также передать аргументы его конструктору: -)
Ответ 2
Только если ISomeInterface
является классом.
Обновление (для уточнения):
Jon Skeet беседа, где он упоминает реализации по умолчанию для интерфейсов. Однако они не являются частью языка С#. Разговор о том, что Джон Скит хотел бы увидеть в будущей версии С#.
В настоящее время единственные реализации по умолчанию выполняются через (возможно, abstract
) базовые классы.
Ответ 3
Может быть, вы ссылаетесь на Injection Dependency? Если при использовании рамки DI (например, Ninject или Unity) вы можете определить экземпляр по умолчанию для каждого интерфейса, а затем использовать его следующим образом:
(если у вас есть интерфейс IWeapon
и Sword
реализует его)
IKernel kernel = new StandardKernel();
kernel.Bind<IWeapon>().To<Sword>();
var weapon = kernel.Get<IWeapon>();
Но Ninject (и большинство других фреймворков IoC) может делать некоторые более умные вещи, например: пусть скажем, что у нас есть класс Warrior
, который принимает IWeapon как параметр в его конструкторе. Мы можем получить экземпляр Warrior
из Ninject:
var warrior = kernel.Get<Warrior>();
Ninject передаст реализацию IWeapon, указанную в конструкторе Warrior
, и вернет новый экземпляр.
Кроме этого, я не знаю какой-либо функции на языке, которая допускает такое поведение.