Можно создать конвертер, объединяющий другие в цепочку, а можно добавить этот механизм к механизму markup extension и тогда цепочку можно записывать в строку, а не иерархически, что иногда более понятно.
А ещё нужно обратное конвертирование поддерживать в базисном классе.
Я понимаю, что сахарок удобен, но что бы он был реально удобен, нужно, чтоб он был ещё и надежен. Да можно отписаться, что у нас есть две сладкие конструкции, которые так и так разворачиваются, но их совместное использование разрушает принцип надежности программы. Сахар на то и сахар, чтоб программист не особо заморачивался с тем что там внутри. Если создали два куска сахара — добавьте третий для их совместного использования. Во первых это не так сложно в данной ситуации, во вторых сахар это все-таки не макро определение, а часть языка и программиста не должно особо волновать, что там внутри. Напротив, компилятор должен продумать возможные проблемы, как он это делает с другими встроенными конструкциями. Или запретить использование этой конструкции в данном месте.
Вот пример элементарного разворота этой конструкции во вполне надежный код:
long position = -1;
var tmpFile = new FileStream("d:\\1.txt", FileMode.OpenOrCreate);
try
{
tmpFile.Position = position;
var file = tmpFile;
//....
}
finally
{
if (tmpFile != null)
((IDisposable)tmpFile).Dispose();
}
При этом переменная file должна определяться всегда внутри try, а конструкция using должна всегда использовать сгенерированную компилятором переменную для вызова Dispose. Тогда все выглядит вполне сладко и надежно. Поправьте, если я ошибаюсь.
Вместо передачи функции-провайдера можно использовать кешированные Expressions:
class Operator<T>{
static readonly Func<T> _new =
Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();
public static Func<T> New { get { return _new; } }
}
Тогда вместо
T t = new T();
можно писать
T t = Operator<T>.New();
Первый вызов будет долгим, потому, что создается и кешируется Expression, но остальные практически равны прямому вызову оператора , а иногда почему-то даже быстрее.
Если память мне не изменяет, статические расширения (типа StaticResource) можно присвоить любому свойству, а вот динамические (Binding, DynamicResource) работают только с DependencyProperty. Если не наследовать конвертер от MarkupExtension, то его можно наследовать от DependencyObject и насоздавать нужных свойств. Но в таком случае пропадает возможность его создания на месте и мы возвращаемся к ресурсам.
Конечно можно.
В принципе есть некоторое преимущество в использовании статического конвертера. Например, если вам нужно создать дата темплейт, включающий конвертер и использовать его для длинного списка элементов в ItemsControl. Тогда новый экземпляр конвертера будет создан, а главное прикреплен к каждому Item. Если же используется статический элемент, то будет создан и тут же уничтожен конвертер как MarkupExtension, а привязанный надолго статический конвертер останется в одном экземпляре. Жаль что тогда теряется возможность использования параметров. Или просто при таком использовании нужно просто воспользоваться старым способом с ресурсами и тогда единичный экземпляр конвертера будет создан как ресурс, а в качестве временного MarkupExtension будет выступать StaticResource. По поводу DynamicResource не уверен, что он сам не зависает в памяти надолго. Я бы использовал ваш вариант для конвертера без параметров и мой для конвертера с параметрами.
Насколько я понимаю достаточно просто вернуть себя из функции ProvideValue, поскольку объект одновременно является и конвертером и уже создан. Так зачем же создавать ещё один? Пользуюсь этой системой уже давно. Пока проблем не заметил.
public override object ProvideValue(IServiceProvider serviceProvider){
return this;
}
Кстати, в таком варианте можно добавлять к Конвертеру кучу параметров и инициализировать их прямо в месте создания и для каждого места разные.
Например:
<Label Content="{Binding Path=Date, Converter={converters:DateConverter Format=ShortString, Calendar=Gregorian}}" />
public class DateTimeToString : ...
{
public override object Convert(...){...}
public string Format{get;set;}
public CalendarType Calendar{get;set;}
}
Параметры конечно только для примера, но иногда нужно определить более одного параметра и ConverterParameter с этим не справляется
Я например больше использую эту комбинацию для выделения слова под курсором. А потом есть вариант скопировать или перенести.
А ещё не люблю зум через ctrl + wheel. Постоянно после уже отпущенного контрола использование колесика вдруг начинает зумить. Я отключил совсем. Ctrl с плюсом/минусом работает лучше.
Я действительно считаю себя новичком, поскольку пишу на JS всего 4-ый месяц. Я хорошо (надеюсь) знаю теорию, но ещё слаб в практике. И ещё я три месяца писал проект на ActionScript 2, но там были классы, хотя под ними скрывался тот же стандарт.
Мне очень нравится гибкость языка, но эта разлюле-малина при отсутствии компилятора и при динамической платформе языка приводит к очень высокой вероятности получить проблему на ровном месте. Приходится строить некие правила для себя и своей группы, чтобы ограничить свободу и получить совместимость кода.
Из первой ссылки я понял, что метод там описанный, очень далек от совершенства, хотя и делает то же, что и мой, только вывернутым образом. Он не работает корректно, если вы в качестве базового используете созданный не им же объект (например из библиотеки). Тогда вызов clazz.prototype = new parent; зовет реальный, а не специальный конструктор и тут уж как повезет. Он так же работет некорректно, если в цепочке более двух классов. Вызов базового класса всегда идет к самому базовому, а не к тому от кого наследовался (хотя конструкторы работают корректно). Я люблю более надежные решения.
Вы про С#? Ну ладно, давайте пару слов о нем.
Если вы вызываете конструктор объекта, то соответственно он исполнится вместе со всеми действиями внутри. При создании объекта, содержащего другие объекты (обычная распространенная практика в С#, как в ОО языке) можно инициализировать (создать) эти объекты в момент конструирования папы или другими средствами, например lazy конструированием по мере надобности. Поскольку любой объект сохраняется по ссылке на него, то можно иметь неинициализированную ссылку до тех пор, пока он вам не понадобится.
Я рад за PHP, но мы вроде бы о JavaScript говорим. А в С# действительно в объекте можно создавать все, включая другие объекты и самое приятное, что они обрабатываются корректно.
Спасибо, конечно, но азбуку прототипирования я прочитал, а заодно и Кроукфорда и javascript.ru. Там очень много полезного. И в частности то, что Appointment.prototype = new Point(); есть зло. А делать надо так:
var Tmp = function() { }
Tmp.prototype = Point.prototype
Appointment.prototype = new Tmp()
Appointment.prototype.constructor = Appointment;
Но дело даже не в этом. Я говорил о mutable объектах. Пример:
function Rect(){}
Rect.prototype.pt1 = new Point();
Rect.prototype.pt2 = new Point();
var r1 = new Rect();
var r2 = new Rect();
r1.pt1.x = 100;
r2.pt1.x = 200;
alert(r1.pt1.x); // 200
оба экземпляра разделяют один и тот же изменяемый объект и изменения в одном влияют на состояние другого, что неправильно.
Re: ЗЫ: eval я использую не в рабочем коде, а как вспомогательную функцию для тестов и только по той причине, что язык/система не предоставляет других средств. Поэтому постоянный парсинг кода меня не волнует. Объекты, требующие создания большого количества экземпляров, я пишу в упрощенном варианте или использую прямое создание объекта только с данными (типа структуры в С#)
Re: ЗЫ2: согласен на 100 %.
Конечно опыт этих фирм наше всё, но к сожалению я у них не работаю, а работаю у нас, где этот опыт опровергается на практике каждый день. И весь его авторитет остается где-то там за стенами нашей фирмы. Я бы и рад им воспользоваться, но не условия дают. (
А ещё нужно обратное конвертирование поддерживать в базисном классе.
Вот пример элементарного разворота этой конструкции во вполне надежный код:
При этом переменная
fileдолжна определяться всегда внутриtry, а конструкцияusingдолжна всегда использовать сгенерированную компилятором переменную для вызоваDispose. Тогда все выглядит вполне сладко и надежно. Поправьте, если я ошибаюсь.Тогда вместо
можно писать
Первый вызов будет долгим, потому, что создается и кешируется Expression, но остальные практически равны прямому вызову оператора , а иногда почему-то даже быстрее.
<Label Content="{Binding Path=Date, Converter={StaticResource dateConverter}, ConverterParameter='Gregorian'}" />А в ресурсах это как обычно создается конвертер.
В принципе есть некоторое преимущество в использовании статического конвертера. Например, если вам нужно создать дата темплейт, включающий конвертер и использовать его для длинного списка элементов в ItemsControl. Тогда новый экземпляр конвертера будет создан, а главное прикреплен к каждому Item. Если же используется статический элемент, то будет создан и тут же уничтожен конвертер как MarkupExtension, а привязанный надолго статический конвертер останется в одном экземпляре. Жаль что тогда теряется возможность использования параметров. Или просто при таком использовании нужно просто воспользоваться старым способом с ресурсами и тогда единичный экземпляр конвертера будет создан как ресурс, а в качестве временного MarkupExtension будет выступать StaticResource. По поводу DynamicResource не уверен, что он сам не зависает в памяти надолго. Я бы использовал ваш вариант для конвертера без параметров и мой для конвертера с параметрами.
public override object ProvideValue(IServiceProvider serviceProvider){ return this; }Кстати, в таком варианте можно добавлять к Конвертеру кучу параметров и инициализировать их прямо в месте создания и для каждого места разные.
Например:
<Label Content="{Binding Path=Date, Converter={converters:DateConverter Format=ShortString, Calendar=Gregorian}}" /> public class DateTimeToString : ... { public override object Convert(...){...} public string Format{get;set;} public CalendarType Calendar{get;set;} }Параметры конечно только для примера, но иногда нужно определить более одного параметра и ConverterParameter с этим не справляется
А ещё не люблю зум через ctrl + wheel. Постоянно после уже отпущенного контрола использование колесика вдруг начинает зумить. Я отключил совсем. Ctrl с плюсом/минусом работает лучше.
Мне очень нравится гибкость языка, но эта разлюле-малина при отсутствии компилятора и при динамической платформе языка приводит к очень высокой вероятности получить проблему на ровном месте. Приходится строить некие правила для себя и своей группы, чтобы ограничить свободу и получить совместимость кода.
Из первой ссылки я понял, что метод там описанный, очень далек от совершенства, хотя и делает то же, что и мой, только вывернутым образом. Он не работает корректно, если вы в качестве базового используете созданный не им же объект (например из библиотеки). Тогда вызов
clazz.prototype = new parent; зовет реальный, а не специальный конструктор и тут уж как повезет. Он так же работет некорректно, если в цепочке более двух классов. Вызов базового класса всегда идет к самому базовому, а не к тому от кого наследовался (хотя конструкторы работают корректно). Я люблю более надежные решения.Если вы вызываете конструктор объекта, то соответственно он исполнится вместе со всеми действиями внутри. При создании объекта, содержащего другие объекты (обычная распространенная практика в С#, как в ОО языке) можно инициализировать (создать) эти объекты в момент конструирования папы или другими средствами, например lazy конструированием по мере надобности. Поскольку любой объект сохраняется по ссылке на него, то можно иметь неинициализированную ссылку до тех пор, пока он вам не понадобится.
Appointment.prototype = new Point();есть зло. А делать надо так:Ну и конечно в конструкторе наследника нужно вызвать конструктор базового класса. Подробности и объяснение смотри на javascript.ru/tutorial/object/inheritance#nasledovanie-na-klassah-funkciya-extend
Но дело даже не в этом. Я говорил о mutable объектах. Пример:
оба экземпляра разделяют один и тот же изменяемый объект и изменения в одном влияют на состояние другого, что неправильно.
Re: ЗЫ: eval я использую не в рабочем коде, а как вспомогательную функцию для тестов и только по той причине, что язык/система не предоставляет других средств. Поэтому постоянный парсинг кода меня не волнует. Объекты, требующие создания большого количества экземпляров, я пишу в упрощенном варианте или использую прямое создание объекта только с данными (типа структуры в С#)
Re: ЗЫ2: согласен на 100 %.