Как зайти в Даркнет?!
25th January, 01:11
6
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
895
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
914
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
906
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4381
0
Помогите пожалуйста решить задачи
24th November, 23:53
6086
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4351
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4396
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Как можно требовать конструктор без параметров для типов, реализующих интерфейс?
Есть ли какой-то выход?
Мне нужно, чтобы все типы, реализующие определенный интерфейс, имели конструктор без параметров, можно ли это сделать?
Я разрабатываю базовый код для других разработчиков в моей компании, чтобы использовать его в конкретном проекте.
Существует процесс, который будет создавать экземпляры типов (в разных потоках), выполняющих определенные задачи, и мне нужно, чтобы эти типы следовали определенному контракту (ergo, интерфейс).
Интерфейс будет внутренним для assembly
Если у вас есть предложение для этого сценария без интерфейсов, я с удовольствием приму его во внимание...
Не хочу быть слишком прямолинейным,но вы неправильно поняли назначение интерфейсов.
Интерфейс означает, что несколько человек могут реализовать его в своих собственных классах, а затем передать экземпляры этих классов другим классам для использования. Творение создает ненужную сильную связь.
Похоже, вам действительно нужна какая-то система регистрации, чтобы люди регистрировали экземпляры полезных классов, реализующих интерфейс, или фабрик, которые могут создавать эти элементы по запросу.
Хуан,
К сожалению, нет никакого способа обойти это в строго типизированном языке. Вы не сможете гарантировать во время компиляции, что классы смогут быть созданы вашим кодом на основе активатора.
(ed: удалено ошибочное альтернативное решение)
Причина в том, что, к сожалению, невозможно использовать интерфейсы, абстрактные классы или виртуальные методы в сочетании с конструкторами или статическими методами. Короткая причина заключается в том, что первые не содержат явной информации о типе, а вторые требуют явной информации о типе.
Конструкторы и статические методы должны иметь явную (прямо там, в коде) информацию о типе, доступную во время вызова. Это необходимо, потому что нет экземпляра класса, который может быть запрошен средой выполнения для получения базового типа, который среда выполнения должна определить, какой фактический конкретный метод вызывать.
Вся суть интерфейса, абстрактного класса или виртуального метода состоит в том, чтобы иметь возможность выполнять вызов функции без явной информации о типе, и это обеспечивается тем фактом, что существует экземпляр, на который ссылаются, который имеет информацию о типе "hidden", не доступную непосредственно вызывающему коду. Так что эти два механизма просто взаимоисключающие. Они не могут использоваться вместе, потому что при их смешивании вы в конечном итоге не получаете никакой конкретной информации о типе вообще нигде, что означает, что среда выполнения не имеет представления, где найти функцию, которую вы просите ее вызвать.
Вы можете использовать ограничение параметра типа
interface ITest<T> where T: new()
{
//...
}
class Test: ITest<Test>
{
//...
}
это одна из причин, по которой я не понимаю, почему он не может быть частью контракта в интерфейсе
Это косвенный механизм. Универсальный позволяет вам "cheat" и отправлять информацию о типе вместе с интерфейсом. Здесь важно помнить, что ограничение не относится к интерфейсу, с которым вы работаете непосредственно. Это не ограничение на сам интерфейс, а на какой-то другой тип, который будет "ride along" на интерфейсе. Боюсь, это лучшее объяснение, которое я могу предложить.
В качестве иллюстрации этого факта я укажу на дыру, которую я заметил в коде Аку. Можно написать класс, который будет хорошо компилироваться, но не будет работать во время выполнения при попытке создать его экземпляр:
public class Something : ITest<String>
{
private Something() { }
}
Что-то происходит от ITest<T>,, но не реализует конструктор без параметров. Он будет компилироваться нормально, потому что String реализует конструктор без параметров. Опять же, ограничение находится на T, и поэтому String, а не на ITest или что-то еще. Так как ограничение на T выполнено, это будет компилироваться. Но он не будет работать во время выполнения.
Чтобы предотвратить некоторые случаи этой проблемы, вам нужно добавить еще одно ограничение к T, как показано ниже:
public interface ITest<T>
where T : ITest<T>, new()
{
}
Обратите внимание на новое ограничение: T : ITest<T>. это ограничение указывает, что то, что вы передаете в параметр аргумента ITest<T>, также должно быть производным от ITest<T>.
Но даже так это не предотвратит все случаи появления дыры. Приведенный ниже код будет хорошо компилироваться, так как A имеет конструктор без параметров. Но поскольку конструктор без параметров B является частным, создание экземпляра B с вашим процессом завершится неудачей во время выполнения.
public class A : ITest<A>
{
}
public class B : ITest<A>
{
private B() { }
}
Поэтому вам нужна вещь , которая может создавать экземпляры неизвестного типа, реализующие интерфейс. У вас есть в основном три варианта: объект фабрики, объект типа или делегат. Вот вам и данность:
public interface IInterface
{
void DoSomething();
}
public class Foo : IInterface
{
public void DoSomething() { /* whatever */ }
}
Использование Type довольно уродливо, но имеет смысл в некоторых сценариях:
public IInterface CreateUsingType(Type thingThatCreates)
{
ConstructorInfo constructor = thingThatCreates.GetConstructor(Type.EmptyTypes);
return (IInterface)constructor.Invoke(new object[0]);
}
public void Test()
{
IInterface thing = CreateUsingType(typeof(Foo));
}
Самая большая проблема с ним заключается в том, что во время компиляции у вас нет никакой гарантии, что Foo действительно имеет конструктор по умолчанию. Кроме того, отражение немного замедляется, если это критический для производительности код.
Наиболее распространенным решением является использование завода:
public interface IFactory
{
IInterface Create();
}
public class Factory<T> where T : IInterface, new()
{
public IInterface Create() { return new T(); }
}
public IInterface CreateUsingFactory(IFactory factory)
{
return factory.Create();
}
public void Test()
{
IInterface thing = CreateUsingFactory(new Factory<Foo>());
}
В приведенном выше примере IFactory-это то, что действительно имеет значение. Factory-это просто класс удобства для классов, которые предоставляют конструктор по умолчанию. Это самое простое и часто лучшее решение.
Третье решение currently-uncommon-but-likely-to-become-more-common-это использование делегата:
public IInterface CreateUsingDelegate(Func<IInterface> createCallback)
{
return createCallback();
}
public void Test()
{
IInterface thing = CreateUsingDelegate(() => new Foo());
}
Преимущество здесь заключается в том, что код является коротким и простым, может работать с любым методом построения и (с closures) позволяет легко передавать дополнительные данные, необходимые для построения объектов.
Я хотел бы напомнить всем, что:
- Писать атрибуты в .NET легко
- Написать инструменты статического анализа в .NET, которые обеспечивают соответствие стандартам компании, очень просто
Написание инструмента для захвата всех конкретных классов, реализующих определенный интерфейс/имеющих атрибут, и проверка наличия конструктора без параметров занимает около 5 минут кодирования. Вы добавляете его в свой шаг после сборки, и теперь у вас есть платформа для любого другого статического анализа, который вам нужно выполнить.
Язык, компилятор, IDE, ваш мозг - все это инструменты. Используй их!
Для создания экземпляра класса активатором не требуется конструктор без параметров. Вы можете иметь параметризованный конструктор и передавать все параметры из активатора. Проверьте MSDN на этом .