Неплохая статейка, описывающая роли ключей /debug /optimize, компилятора C#:
http://blogs.msdn.com/ericlippert/archive/2009/06/11/what-does-the-optimize-switch-do.aspx
Неплохая статейка, описывающая роли ключей /debug /optimize, компилятора C#:
http://blogs.msdn.com/ericlippert/archive/2009/06/11/what-does-the-optimize-switch-do.aspx
Небольшой обзор того, что нам готовит новая версия спецификации языка.
Смена первой цифры произошла благодаря четырём основным фичам:
Сегодня подробней рассмотрим первую.
Dynamycally Typed Objects
Динамическая система типов является, пожалуй, самым основным нововведением языка. Судя по лекциям с PDC 2008, c точки зрения архитектуры .NET добавился еще один компонент – DLR (dynamic object runtime), являющийся, по сути, надстройкой над CLR. С точки зрения языка добавилось ключевое слово dymanic. И одноименный тип добавился в .NET Type System.
Какое время назад Microsoft Research утверждала, что реализация будет происходить так: на момент компиляции объект будет не типизирован, а тэгирован, и на момент выполнения тег заменяется на свежевычесленный тип и вместо “неопределенного” типа подставляется “настоящий” и дальше все работает по старой схеме. Собственно DLR этим и должен заниматься.
Но что же происходит на самом деле?
Read the rest of this entry »
В связи с особенностями работы монитора при подключении второго источника изображения при активном первом, написал небольшую программку, которая посылает сообщение, прекращающее выдачу видеосигнала на дисплей. Сообщение идентично тому, что посылается при отключении дисплея в режиме PowerSaving.
За все отвечает системное сообщение WM_SYSCOMMAND с параметрами SC_MONITORPOWER и 2. LPARAM со значением 2 соответствует отключению дисплея. Значение параметра -1 – включает дисплей, 1 – вводит дисплей в режим Stand By (в основном актуально для ноутбуков).
Код получился крайне незамысловатый:
static class Program { [DllImport("user32.dll")] static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); static IntPtr SC_MONITORPOWER = new IntPtr(0xF170); const uint WM_SYSCOMMAND = 0x0112; static IntPtr MONITOR_OFF = new IntPtr(2); static IntPtr HWND_BROADCAST = new IntPtr(0xffff); [STAThread] static void Main() { SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF); } }
Позволю себе немного порассуждать на тему реализации UI обычных десктопных приложений.
Во-первых, разговоров о том, что UI правильнее всего описывать с помощью конечных автоматов была тьма-тьмущая. В целом это очень верно – логика работы заранее продумана и отточена. В каждый момент времени презентационная часть программы может находится в одном из состояний и, посредством манипуляции пользователем доступных контролов, переходить в одно из возможных целевых состояний. При грамотном построении автомата на этапе проектирования, сбоев в работе быть не должно. Потому автомат как паттерн поведения для “витрины” приложения наиболее гуманный выбор.
Во-вторых, при реализации GUI я предпочитаю пользоваться парадигмой MVP (Model-View-Presenter). Почему не MVC? Потому, что лично мне MVC (Model-View-Control) нравится гораздо меньше. Одно из основных различий этих подходов как раз и позволяет мне сделать однозначный выбор. Я считаю, что выводить половину функциональности презентационной части из диалога с пользователем стратегически неверно. Т.е. ответ от приложения приходит в окно, а весь feedback от пользователя идет контроллеру, тем самым заставляя его решать задачи, с которыми бы отлично справилось окно. Но самое интересное о применении MVP я опишу в далее.
В-третьих, есть мнение, что контроллеру (в случае MVC) или презентору (в случае MVP) совершенно неважно нажал ли пользователь кнопку, поменял ли значение комбобокса или повазюкал слайдер, ему должно все приходить в терминах некоторой внутренней структуры. Т.е., по-хорошему, между котроллером/презентором и view должен быть некоторый метауровень предназначенный для преобразования сущностей из одного архитектурного слоя в другой. Вот тут нам и приходит на помощь подход MVP, изолированность пользователя от презентера не вынуждает “рассказывать” ему об особенностях работы пользователя. Его не надо знакомить с интерфейсам в целом к его работе не имеющим отношения. Пользователю в целом предоставлена свобода действий в рамках интерактивного окна (или набора окон), все его действия ограничиваются манипуляциями с контролами на форме.
В-четвертых, при реализации автомата, одним из самых применимых шаблонов является шаблон Visitor. Потому при создании слоя для преобразования хэндлеров контролов в термины модели приложения необходимо четко продумать интерфейсы, о них я напишу ниже.
Вариантом применения такого подхода может быть приложение имеющее, например, иконку в трее и основное окно и в зависимости от текущего состояния приложения иконка может иметь свое состояние, свое контекстное меню, а окно программы свой набор контролов, выделенный таб и т.п.
Подводя итог всему вышеперечисленному, позволю себе привести пример реализации небольшого приложения.
Вот так для презентора должна выглядеть логика работы UI:
Для начала определим делегаты и интерфейс с ними согласующийся. Вообще говоря часто можно обойтись двумя типами с параметром и без:
delegate void Action_WO_EventArgumentHandler(); delegate void Actoin_W_EventArgumentHandler<T> (T ea); interface IUserActions { event Action_WO_EventArgumentHandler OnUserWantsSomething; event Actoin_W_EventArgumentHandler<DateTime> OnUserWantsDateTime; }
Использование generic добавляет известную гибкость при определении типа параметра.
Далее добавляем интерфейс для управления текущим состоянием контрола:
interface IStateSetters { void SetContentForStateOne(); void SetContentForStateTwo(); }
Теперь в теле класса нашего контрола реализуем оба интерфейса:
Далее со всеми необходимыми контролами поступаем схожим образом.
class FEControl1 : Control, IStateSetters, IUserActions { public FEControl1() : base() { // Конструктор-шманструктор } public void SetContentForStateOne() { // Делаем вское c содержимым контрола для перевода его в StateOne } public void SetContentForStateTwo() { // Делаем вское c содержимым контрола для перевода его в StateTwo } public event Action_WO_EventArgumentHandler OnUserWantsSomething; public void OnClickAction() { if (OnUserWantsSomething != null) OnUserWantsSomething(); // Обрабатываем вское, вызываем события контрола и т.п. } public event Actoin_W_EventArgumentHandler<DateTime> OnUserWantsDateTime; public void OnOtherClickAction() { if (OnUserWantsDateTime != null) OnUserWantsDateTime(DateTime.Now); // Обрабатываем вское, вызываем события контрола и т.п. } }
Теперь наша задача реализовать Visitor
class FEControlVisitor { List<IStateSetters> m_lstStateChangerList = new List<IStateSetters>(); public void SetState() { foreach (IStateSetters st in m_lstStateChangerList) { if(ProgramData.State == States.StateOne) st.SetContentForStateOne(); else if(ProgramData.State == States.StateTwo) st.SetContentForStateTwo(); } } }
Тут полет фантазии практически неограниченный. ProgramData, например, может быть Singleton, States – enum. ProgramData можно передавать в качестве параметра функции. Для опередления состояния можно устроить каскадный if, можно устроить switch, в зависимости от иерархии состояний. А можно вообще для каждого состояния держать свою функцию, в которой обходится лист подписанных на Visitor контролов.
Для случая подписки на события все происходит по схожему сценарию. Визитор обходит подписчиков и добавляет в хэндлер эвента метод, который будет его обрабатывать. Процедура в целом схожая с SetState().
Как мне кажется, описаный подход наиболее действенный и срабатывал неоднократно. Прекрасная масштабируемость в плане добавления котнролв, измемения поведения контролов, ну вообще одни плюсы!
Рассмотрим реализацию полиморфизма в С#. Итак есть два основных способа, первый, посредством абстрактных классов, второй, посредством интерфейсов. Напомню свойства каждого из них.
Абстрактные классы
Пример реализации:
abstract class CFile { public abstract void Open(); public abstract void Save(); } class CFileNewtype : CFile { public override void Open() { Console.WriteLine("Open method for Newtype File"); } public override void Save() { Console.WriteLine("Save method for Newtype File"); } } class CFileOldtype : CFile { public override void Open() { Console.WriteLine("Open method for Oldtype File"); } public override void Save() { Console.WriteLine("Save method for Oldtype File"); } }
Абстрактные классы имеют ряд свойств:
Интерфейсы
Пример реализации:
interface IFileTypesProvider { void Open(); void Save(); } class CFileNewtype : IFileTypesProvider { public void Open() { Console.WriteLine("Open method for Newtype File"); } public void Save() { Console.WriteLine("Save method for Newtype File"); } } class CFileOldtype : IFileTypesProvider { public void Open() { Console.WriteLine("Open method for Oldtype File"); } public void Save() { Console.WriteLine("Save method for Oldtype File"); } }
Свойства интерфейсов:
Так когда стоит применять реализацию полиморфизма через абстрактные классы, а когда через интерфейсы?