1/29/2008

Классификатор может расплавить мозг.

Простая задача: найти код классификации ПО, которое использует Windows Workflow Foundation. Найти код надо на сайте «ФЕДЕРАЛЬНАЯ СЛУЖБА ПО ИНТЕЛЛЕКТУАЛЬНОЙ СОБСТВЕННОСТИ, ПАТЕНТАМ И ТОВАРНЫМ ЗНАКАМ (РОСПАТЕНТ)». Я не кричу – это они J.

Так вот .... найти классификатор было нелегко. Для последователей привожу ссылку: «Международная патентная классификация
(8-я редакция)
». Шок был, когда увидел следующий список:

Раздел A УДОВЛЕТВОРЕНИЕ ЖИЗНЕННЫХ ПОТРЕБНОСТЕЙ ЧЕЛОВЕКА

Раздел B РАЗЛИЧНЫЕ ТЕХНОЛОГИЧЕСКИЕ ПРОЦЕССЫ;ТРАНСПОРТИРОВАНИЕ

Раздел C ХИМИЯ; МЕТАЛЛУРГИЯ

Раздел D ТЕКСТИЛЬ; БУМАГА

Раздел E СТРОИТЕЛЬСТВО; ГОРНОЕ ДЕЛО

Раздел F МЕХАНИКА; ОСВЕЩЕНИЕ; ОТОПЛЕНИЕ; ДВИГАТЕЛИ И НАСОСЫ; ОРУЖИЕ И БОЕПРИПАСЫ; ВЗРЫВНЫЕ РАБОТЫ

Раздел G ФИЗИКА

Раздел H ЭЛЕКТРИЧЕСТВО

Догадайтесь, где здесь будет про ПО? Хе-хе.

Первое, куда зашел, это был «Раздел A». Логика простая – ПО помогает жить, мне уж точно J. Потом посетил «Раздел B». Логика тоже понятна – есть слово «технологические». Загляните, там такое .... и так много; это не просто ужас, а ужас-ужас. J

Зашел в «Раздел H», потому что ПО работает на компьютерах, которые пока что потребляют электричество.

Короче, будете в классификаторе, идите прямо в G06Q – «Системы обработки данных или способы, специально предназначенные для административных, коммерческих, финансовых, управленческих, надзорных или прогностических целей; системы или способы, специально предназначенные для административных, коммерческих, финансовых, управленческих, надзорных или прогностических целей, не предусмотренные в других подклассах».

Да-да, ПО в «Раздел G». Ну, где еще может быть про ПО, как не в Г? Бывает, устаешь, и все ПО хочется послать в раздел У. J
Пойду прогуляюсь ...



P.S.
У - в смысле унитаз J

1/28/2008

Закон третьей стороны или как возникают конфликты

Закон третьей стороны гласит: непрекращающиеся конфликты поддерживаются третьей стороной. Под третьей стороной понимают любого, кто посредством ложных сообщений создает раздоры между двумя сторонами (людьми, или человеком и группой, или между двумя группами). Автор закона  - Рон Хаббард (американский исследователь, философ). Закон применим на любом уровне - семьи, компании, государства. Существует стандартная технология обнаружения и обезвреживание третьей стороны – личное и открытое общение!

 

P.S. ака ЗЫ

Ну, все - теперь и мой блог хакеры атакуют в рамках борьбы с саентологами J.

 

P.P.S. ака ЗЗЫ

Disclaimer cпециально для хакеров: то, что я привожу здесь имя основателя саентологии – не означает мою приверженность J. Не ломайте мой блог, плиз J.

 

Для тех кто не знает причем здесь хакеры и саентологи: война у них сетевая посредством DDos-атак. А мне что с этого, спросит, как говорят, проницательный читатель J? А то, что от этих войн сети забиваются DDos-барахло-пакетами, и до многих сайтов не достучаться; даже почту не мог получить почти весь день.

Короче,  хватит воевать; миру мир, конец войне J.

1/27/2008

Про LINQ to SQL и INNER JOIN

Например, в БД есть две таблицы и ограничение:


Request:

[Id] [uniqueidentifier] NOT NULL

[Date] [datetime] NOT NULL

 

Form:
[RequestId] [uniqueidentifier] NOT NULL,

[Key] [nvarchar](10) COLLATE Cyrillic_General_CI_AS NULL,

[Value] [nvarchar](4000) COLLATE Cyrillic_General_CI_AS NOT NULL,

[Id] [uniqueidentifier] NOT NULL,

 

Ограничение:

CONSTRAINT [Request_Form] FOREIGN KEY([RequestId]) REFERENCES [dbo].[Request] ([Id])

 

В переводе на человеческий J:
есть таблица запросов
Request, в которой хранятся идентификаторы и даты, а также есть таблица Form, в которой хранятся пары Key и Value, при этом для одного Request может быть несколько строк в Form.

 

Например, надо из Form выбрать 20-ть Value, которым соответствуют Key = “mail”, и также значение Date из родительского Request.

На SQL этот запрос выглядит следующим образом:

 

SELECT TOP (20) [t1].[Date], [t0].[Value] AS [Mail]

FROM [Form] AS [t0]

INNER JOIN [Request] AS [t1] ON [t1].[Id] = [t0].[RequestId]

WHERE [t0].[Key] = @p0

 

Но не надо бежать и изучать SQL с его «страшными» INNER JOIN'ами. Можно использовать LINQ to SQL (часть язык C# 3.0), который SQL-запрос сформирует сам. Вот как он выглядит:

var mails = from frm in dc.Form

                        where frm.Key == "mail"

                        select new { Date = frm.Request.Date, Mail = frm.Value };

 

где dc – это экземпляр наследника DataContext'а.

Пример, использования в A
SP.NET:

<asp:DataGrid runat="server" ID="_MailList" AutoGenerateColumns="true" Width="100%"

           BorderWidth="0" AlternatingItemStyle-BackColor="#e0e0e0">

</asp:DataGrid>

_MailList.DataSource = mails.Take(20);

_MailList.DataBind();        // запрос к SQL Server’у

 

Наследник DataContext’а формируется автоматически с помощью MSLinqToSQLGenerator'а на основе следующего .dbml-файла (далее фрагмент):

<Table Name="" Member="Form">

    <Type Name="Form">

      <Column Name="RequestId" Type="System.Guid" CanBeNull="false" />

      <Column Name="Key" Type="System.String" DbType="nvarchar(10)" CanBeNull="false" />

      <Column Name="Value" Type="System.String" CanBeNull="false" />

      <Column Name="Id" Type="System.Guid" IsPrimaryKey="true" CanBeNull="false" />

      <Association Name="Request_Form" Member="Request" ThisKey="RequestId" Type="Request" IsForeignKey="true" />

    </Type>

</Table>

<Table Name="" Member="Request">

    <Type Name="Request">

      <Column Name="Id" Storage="_Id" Type="System.Guid" IsReadOnly="true" IsPrimaryKey="true" CanBeNull="false" />

      <Column Name="Date" Type="System.DateTime" IsReadOnly="true" CanBeNull="false" />

      <Association Name="Request_Form" Member="Form" OtherKey="RequestId" Type="Form" />

    </Type>

</Table>

 

Знать .dbml -формат необязательно, потому что в Visual Studio 2008 есть графический редактор, с помощью которого достаточно легко создать схему БД и отношения между таблицами.

Кстати, у DataContext есть метод CreateDatabase(), который предназначен для создания файлов БД (.mdb-файл  - SQL Server; для SQL Server CE не проверял, но вроде тоже поддерживает) на основе .dbml-файла.

Производители клавиатур терпят убытки, а жизнь у меня и коллег становится немного легче J.

1/19/2008

Асинхронные операции, C# 3.0 и Extension Methods

В WinForms Application есть ограничение: нельзя обращаться к методам контрола из потока, отличного от того, в котором был создан контрол. Т.е. если контрол был создан в потоке №1, затем был запущен поток №2 для длительной обработки данных, то из потока №2 нельзя обратиться к контролу – будет System.InvalidOperationException: «Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on».

 

Чтобы обойти это ограничение, у контролов существует метод BeginInvoke. Ниже пример использования BeginInvoke.

protected override void OnHandleCreated(EventArgs e)

{

    base.OnHandleCreated(e);

 

    Label lbl = new Label();

    lbl.Parent = this;

    lbl.Dock = DockStyle.Fill;

 

    // выполняется в основном/текущем потоке

    WaitCallback cb = delegate(object state)

    {

        lbl.Text = "Thread " + Thread.CurrentThread.ManagedThreadId + "; " + state + "; " + DateTime.Now;

    };

 

    // выполняется в рабочем потоке

    MethodInvoker mi = delegate()

    {

        for (int i = 0; i < 100; i++)

        {

            // "присоединиться" к основному потоку и передать в него данные

            lbl.BeginInvoke(cb, "Hello, from thread " + Thread.CurrentThread.ManagedThreadId);

 

            // имитация длительной обработки

            System.Threading.Thread.Sleep(1000);

        }

    };

    // запустить рабочий поток

    mi.BeginInvoke(null, null);

}

 

Этот же пример можно переписать по-другому, и «присоединение» к основному потоку перенести в делегат WaitCallback:

 

protected override void OnHandleCreated(EventArgs e)

{

    base.OnHandleCreated(e);

 

    Label lbl = new Label();

    lbl.Parent = this;

    lbl.Dock = DockStyle.Fill;

 

    // выполняется в основном/текущем потоке

    WaitCallback cb = null;

    cb = delegate(object state)

    {

        if (lbl.InvokeRequired)

        {

            // "присоединиться" к основному потоку и передать в него данные

            lbl.BeginInvoke(cb, state);

        }

        else

        {

            lbl.Text = "Thread " + Thread.CurrentThread.ManagedThreadId + "; " + state + "; " + DateTime.Now;

        }

    };

 

    // выполняется в рабочем потоке

    MethodInvoker mi = delegate()

    {

        for (int i = 0; i < 100; i++)

        {

            cb("Hello, from thread " + Thread.CurrentThread.ManagedThreadId);

 

            // имитация длительной обработки

            System.Threading.Thread.Sleep(1000);

        }

    };

    // запустить рабочий поток

    mi.BeginInvoke(null, null);

}

 

Теперь представим, что нам надо написать метод, который ничего не знает про контролы, при этом он должен создать рабочий поток, выполнить какую-то работу и затем вызвать callback в основном потоке.

 

В такой ситуации поможет AsyncOperation:

 

public static void Method(WaitCallback cb)

{

    // "запомнить" основной/текущий поток

    AsyncOperation ao = AsyncOperationManager.CreateOperation(null);

    // будет вызван  в основном/текущем потоке

    SendOrPostCallback cbinner = delegate(object state)

    {

        cb(state);

    };

    // будет вызван из рабочего потока

    MethodInvoker mi = delegate()

    {

        // имитация длительной обработки

        System.Threading.Thread.Sleep(1000);

       

        // "присоединиться" к основному потоку (вызвать cbinner) и передать в него данные

        ao.Post(cbinner, "Hello, from thread " + Thread.CurrentThread.ManagedThreadId);

    };

    // запустить рабочий поток

    mi.BeginInvoke(null, null);

}

 

Пример использования метода Method:

(почти как в Comedy Club: – А как называется ваша книга? – Моя книга, называется «Книга» ... а как еще книга может называться? :)

 

protected override void OnHandleCreated(EventArgs e)

{

    base.OnHandleCreated(e);

 

    // создать контрол

    Label lbl = new Label();

    lbl.Dock = DockStyle.Fill;

    lbl.Parent = this;

 

    Method(delegate(object state)

    {

        lbl.Text = (string) state;

    });

}

 

В C# 3.0 вызов метода Method можно сократить и написать так:

 

Method(state =>

{

    lbl.Text = (string) state;

});

 

или так:

 

Method(state => lbl.Text = (string) state);

 

В C# 3.0 еще и не такое можно J.

Например:

 

protected override void OnHandleCreated(EventArgs e)

{

    base.OnHandleCreated(e);

 

    // создать контрол

    Label lbl = new Label();

    lbl.Dock = DockStyle.Fill;

    lbl.Parent = this;

 

    lbl.Start(() =>

        {

            // имитация длительной обработки

            System.Threading.Thread.Sleep(1000);

            return "Hello, from thread " + Thread.CurrentThread.ManagedThreadId;

        },

        state =>    // в state находится значение, которое вернет return

        {

            lbl.Text = (string)state;

        });

}


Не пытайтесь найти описание метода Label.Start в MSDN, его там нет, и Visual Studio IntelliSense исправен. Дело в том, что Start определен как Extension Methods в отдельном классе.

Например:
(имя класса ни на что не влияет)

 

public static class AsyncOperationEx

{

    public static void Start(this Control c, Method mi, SendOrPostCallback cb)

    {

        AsyncOperation ao = AsyncOperationManager.CreateOperation(null);

        SendOrPostCallback cbinner = state => cb(state);

        MethodInvoker minner = () => ao.Post(cbinner, mi());

        minner.BeginInvoke(null, null);
    }

 

    public delegate object Method();

}

 

Когда я впервые увидел примеры с таким синтаксисом, подумал -  пора идти в садовники J. Привык. Иногда бывает, конечно, взгляд прилипает ненадолго к строке кода, но это не страшно .... то ли еще будет .... c F# J.

 

1/18/2008

MySpace пришел в Россию

На карте MySpace появилась Россия. При открытии страницы http://ru.myspace.com/ все было на английском J. Небольшая задержка, и всплыл диалог с предложением нажать на кнопку Continue. Только после ее нажатия появилась страница на русском с текстом «Добро пожаловать на сайт MySpace на русском языке (бета-версия). Комментарии и предложения сюда ;-)».

И что теперь будет с vkontakte.ru? С него и так многие бегут на facebook.com (хотя он не локализован), а теперь побегут на myspace J.

 

1/17/2008

Пример использования IServiceProvider

Задача: надо передать текст из объекта №1 в объект №2 (определен в сборке №2 , а объект №1 в сборке №1). При передаче данных объект №1 указывает тип текста, например:

public enum TextType

{

    // для обработки можно использовать IHandler1 или IHandler2

    ShortText,

    // для обработки можно использовать IHandler3 или IHandler4

    LongText,

    // для обработки можно использовать IHandler5 или IHandler6

    SecretText,

}

 

А также объект №1 передает заголовок текста и должен предоставить объекту №2 доступ к соответствующим обработчикам IHandler*, которые объект №2 может использовать как ему вздумается или может вообще не использовать. При этом все IHandler* достаточно «тяжелые» и (главное) у них нет ничего общего!

 

Кривое решение: создаем Data Transfer Object (DTO):
public class DTO

{

    // ссылка на Object1 необходима, потому что именно Object1 знает где взять реализацию IHandler*

    internal DTO(Object1 owner)

    {

        _Owner = owner;

    }

    private Object1 _Owner;

   

    public string Title { get; internal set; }

    public DataType DataType { get; internal set; }

 

    // создается по-запросу

    public IHandler1 Handler1

    {

        get

        {

            if(_Handler1 != null)

                _Handler1 = _Owner.CreateHandler(typeof(IHandler1));

           

            return _Handler1;

        }

    }

    private IHandler1 _Handler1;

    /*

     * далее идут определения остальных IHandler*

     */

}

 

Минусы: 1) DTO «привязан» к Object1, т.е. при запросе одного из IHandler* надо обязательно обращаться к Object1;  2) много кода с определениями свойств.

 

Решение: создаем Data Transfer Object (DTO) и реализуем в нем IServiceProvider:

public class DTO : IServiceProvider

{

    // доступен для объекта №1, но недоступен для объекта №2

    internal ServiceContainer Services { get; set; }

 

    // доступен для объекта №2 через IServiceProvider

    object IServiceProvider.GetService(Type serviceType)

    {

        return (this.Services != null) ? this.Services.GetService(serviceType) : null;

    }

 

    public string Title { get; internal set; }

    public DataType DataType { get; internal set; }

}



Кода стало намного меньше и нет привязки к Object1. Т.е. мы полностью избавились от минусов кривого решения.
Пример использования:

 

DTO dto = new DTO() { DataType = DataType.ShortText, Services = new ServiceContainer() };

switch(dto.DataType)

{

    case DataType.ShortText:

        dto.Services.Add<IHandler1>((c, t) =>Factory1.CreateHandler());

        dto.Services.Add< IHandler2>((c, t) =>Factory2.CreateHandler());

        break;

    ...

}

 

Вопрос: откуда у DTO.Services появился метод Add<T>?
Ответ
: это Extension Method, см. ServiceModelHelpers.