(добавление ответа, потому что примеров с универсальными символами Generics недостаточно)
// Source
List<Integer> intList = Arrays.asList(1,2,3);
List<Double> doubleList = Arrays.asList(2.78,3.14);
List<Number> numList = Arrays.asList(1,2,2.78,3.14,5);
// Destination
List<Integer> intList2 = new ArrayList<>();
List<Double> doublesList2 = new ArrayList<>();
List<Number> numList2 = new ArrayList<>();
// Works
copyElements1(intList,intList2); // from int to int
copyElements1(doubleList,doublesList2); // from double to double
static <T> void copyElements1(Collection<T> src, Collection<T> dest) {
for(T n : src){
dest.add(n);
}
}
// Let's try to copy intList to its supertype
copyElements1(intList,numList2); // error, method signature just says "T"
// and here the compiler is given
// two types: Integer and Number,
// so which one shall it be?
// PECS to the rescue!
copyElements2(intList,numList2); // possible
// copy Integer (? extends T) to its supertype (Number is super of Integer)
private static <T> void copyElements2(Collection<? extends T> src,
Collection<? super T> dest) {
for(T n : src){
dest.add(n);
}
}
Рассмотрите взгляд на аспектно-ориентированное решение как PostSharp, который вводит код после факта на основе пользовательских атрибутов. Это - противоположность предварительного компилятора, но может дать Вам вид функциональности, которую Вы ищете (уведомления PropertyChanged и т.д.).
я должен создать препроцессор C#? Действительно ли там каждый доступен, который делает простые вещи, которые я хочу сделать?
можно всегда использовать препроцессор C - C# достаточно близок, мудр синтаксисом. M4 является также опцией.
Я знаю, что много людей думает, что короткий код равняется изящному коду, но это не верно.
пример, который Вы предлагаете, отлично решен в коде, поскольку Вы показали так, к чему Вы нуждаетесь в директиве препроцессору? Вы не хотите "предварительно обрабатывать" свой код, Вы хотите, чтобы компилятор ввел некоторый код для Вас в Ваших свойствах. Это - общий код, но это не цель препроцессора.
С Вашим примером, Куда Вы помещаете предел? Очевидно это удовлетворяет шаблон "наблюдатель" и нет сомнения, что который будет полезен, но существует много вещей, которые были бы полезны, которые на самом деле сделаны, потому что код обеспечивает гибкость , где, поскольку препроцессор не делает. При попытке реализовать общие шаблоны через директивы препроцессору, то Вы закончите препроцессором, который должен быть столь же мощным как сам язык. Если Вы хотите к , обрабатывают Ваш код по-другому использование директива препроцессору , но если Вы просто хотите фрагмент кода, затем находят иначе, потому что препроцессор не был предназначен, чтобы сделать это.
Основным аргументом против создания pre-rocessor для C# является интеграция в Visual Studio: потребовало бы много усилий (если вообще возможный), чтобы заставить intellisense и новую фоновую компиляцию работать беспрепятственно.
Альтернативы должны использовать плагин производительности Visual Studio как ReSharper или CodeRush. Последний имеет - в меру моего знания - несопоставленная система шаблонной обработки и идет с превосходным рефакторинг инструмент.
Другой вещью, которая могла быть полезной в решении точных типов проблем, к которым Вы обращаетесь, является платформа AOP как PostSharp.
можно затем использовать пользовательские атрибуты для добавления общей функциональности.
Для получения названия в настоящее время выполняемого метода можно посмотреть на отслеживание стека:
public static string GetNameOfCurrentMethod()
{
// Skip 1 frame (this method call)
var trace = new System.Diagnostics.StackTrace( 1 );
var frame = trace.GetFrame( 0 );
return frame.GetMethod().Name;
}
, Когда Вы находитесь в методе набора свойств, имя является set_Property.
Используя ту же технику, можно также запросить исходный файл и строку/информацию о столбце.
Однако я не сравнивал этого, создавая объект stacktrace, после того как для каждого набора свойств могла бы быть слишком трудоемкая операция.
Если бы я разрабатывал следующую версию C#, то я думал бы о каждой функции, имеющей автоматически включенную локальную переменную, содержащую название класса и название функции. В большинстве случаев оптимизатор компилятора вынул бы его.
я не уверен, что существует большая часть спроса на такую вещь все же.
@Jorge записал: Если Вы хотите обработать свой код по-другому использование директива препроцессору, но если Вы просто хотите фрагмент кода, затем находят иначе, потому что препроцессор не был предназначен, чтобы сделать это.
Интересный. Я действительно не полагаю, что препроцессор обязательно прокладывает себе путь. В примере, если, я делаю простую текстовую замену, которая в гармонии с определением препроцессора на Википедия .
, Если это не надлежащее использование препроцессора, что мы должны назвать простой текстовой заменой, которая обычно должна происходить перед компиляцией?
Я думаю, что вы, возможно, упускаете одну важную часть проблемы при реализации INotifyPropertyChanged. Вашему потребителю нужен способ определения названия свойства. По этой причине имена ваших свойств должны быть определены как константы или статические строки, доступные только для чтения, чтобы потребителю не приходилось «угадывать» имена свойств. Если бы вы использовали препроцессор, как бы потребитель узнал, что такое строковое имя свойства?
public static string MyPropertyPropertyName
public string MyProperty {
get { return _myProperty; }
set {
if (!String.Equals(value, _myProperty)) {
_myProperty = value;
NotifyPropertyChanged(MyPropertyPropertyName);
}
}
}
// in the consumer.
private void MyPropertyChangedHandler(object sender,
PropertyChangedEventArgs args) {
switch (e.PropertyName) {
case MyClass.MyPropertyPropertyName:
// Handle property change.
break;
}
}
Если вы готовы отказаться от C #, вы можете попробовать язык Boo , который имеет невероятно гибкую поддержку макросов через AST (Абстрактное синтаксическое дерево) манипуляции. Это действительно здорово, если вы можете отказаться от языка C #.
Дополнительные сведения о Boo см. В следующих связанных вопросах: