Сопоставление match типа System.Type
От: CodingUnit Россия  
Дата: 29.01.10 12:16
Оценка:
Здравствуйте, хотел обратиться за помощью разьяснить мне возможности конструкции match в сопоставлении типов, имеется задача, что получается тип Type при отражении типа свойства и далее надо для разных типов произвести отдельные действия, конечный объект свойства при этом еще не существует, если писать так, то компилятор выдает ошибку "invalid pattern":
def CheckType(t : Type)
{
| typeof(bool) => ...
| typeof(byte) => ...
| typeof(int) => ...
}


Сопоставление с конкретным типом не имеет смысла, потому что Type это не bool
{
| bool => // ошибка
}


и все другие варианты is, as не дают положительного результата, единственно что получилось это с помощью нескольких выражений if else сделать что нужно, при этом код выглядит нагруженно и не дает сравнить Type с Type ругаясь на сравнение ссылок и необходимо делать приведение Type к object, чтобы все заработало. Вопрос следующий возможно ли в текущем синтаксисе производить сопоставление типа Type, определяя тип, если нет то можно ли ввести такую возможность в синтаксис (посредством макросов или еще как то), так как такая задача встречается часто при отражении, в C# очень смущают конструкции типа
object obj;

if (obj is Customer)
{
  Customer cust=obj as Customer;
  ... действия на экземпляре Customer
}
if (obj is AnotherCustomer)
{
  AnotherCustomer cust=obj as AnotherCustomer;
  ...
}

хотелось бы от них отказаться в пользу удобного синтаксиса, что и привело меня к Nemerle.
Re: Сопоставление match типа System.Type
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 13:17
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Здравствуйте, хотел обратиться за помощью разьяснить мне возможности конструкции match в сопоставлении типов, имеется задача, что получается тип Type при отражении типа свойства и далее надо для разных типов произвести отдельные действия, конечный объект свойства при этом еще не существует, если писать так, то компилятор выдает ошибку "invalid pattern":


CU>def CheckType(t : Type)

CU>{
CU>| typeof(bool) => ...
CU>| typeof(byte) => ...
CU>| typeof(int) => ...
CU>}

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

CU>Вопрос следующий возможно ли в текущем синтаксисе производить сопоставление типа Type, определяя тип, если нет то можно ли ввести такую возможность в синтаксис (посредством макросов или еще как то), так как такая задача встречается часто при отражении, в C# очень смущают конструкции типа


Можно конечно делать так:
def CheckType(t : Type)
{
  | _ when t.Equals(typeof(bool)) => ...
  | _ when t.Equals(typeof(byte)) => ...
  | _ when t.Equals(typeof(int))  => ...
}

но особого смысла в этом нет.

CU>object obj;


CU>if (obj is Customer)

CU>{
CU>Customer cust=obj as Customer;
CU>... действия на экземпляре Customer
CU>}
CU>if (obj is AnotherCustomer)
CU>{
CU>AnotherCustomer cust=obj as AnotherCustomer;
CU>...
CU>}

Собсвтенно паттерн "is" как раз без проблем можно использоать:
def CheckType(_ : object)
{
  | x is bool => // здесь x имеет тип bool
  | x is byte => // здесь x имеет тип byte
  | x is int  => // здесь x имеет тип int
  | _         => // в ином случае ...
}


Важно понимть, что паттерн-матчинг позволяет распозновать образцы на основании типа объекта или его структуры. Он не позволяет (за исключением использования защиты "when") сравнивать Type для любых типов — это один и тот же тип объектов. Следовтательно можно создать паттерн который будет разбирать структуру объектов этого типа, но отличить их о н не может.
Скажем можно конечно распознавать типы таким образом:
def сheckType(t : Type)
{
  | Type where (FullName="System.Bool")  => WriteLine("bool");
  | Type where (FullName="System.Byte")  => WriteLine("byte");
  | Type where (FullName="System.Int32") => WriteLine("int");
  | _ => WriteLine("xz")
}

сheckType(typeof(byte));

Но зачем так извращаться когда можно просто сравнивать имя?
Ведь так проще:
def сheckType(t : Type)
{
  match (t.FullName)
  {
    | "System.Bool"  => WriteLine("bool");
    | "System.Byte"  => WriteLine("byte");
    | "System.Int32" => WriteLine("int");
    | _ => WriteLine("xz")
  }
}

сheckType(typeof(byte));
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Сопоставление match типа System.Type
От: CodingUnit Россия  
Дата: 29.01.10 13:56
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>На то у типов есть свойство FullName. А пытаться сравнивать экземпляры типа Type вообще опасно, так как они могут представлять типы загруженные из разных сборок. При этом казалось бы одинаковые типы не будут считаться идентичными.


Спасибо за ответ, все таки кажется редкой такая ситуация когда могут быть загружены одинаковые типы из разных сборок, это скорее исключительная ситуация, а чаще приходится сравнивать встроенные типы, которые соответствуют одной версии типа в библиотечной сборке, может вы подскажите или дадите ссылку когда такая ситуация может встречаться, потому что на данный момент в C# только так и поступаю, сначала пробовал именно тот вариант с сравнением имени, но это сказывается на производительности, ведь сравнение двух строк в реальном времени не такая простая операция как сравнение двух ссылок, при том что по определению CLR ссылки Type оригинальны для каждого типа и равны для одинаковых типов. Поэтому все же вариант с when кажется более приемлемым, но прошу разъяснить ситуацию в потребности избегать сравнения ссылок через сравнение имен.


VD>Можно конечно делать так:

VD>
VD>def CheckType(t : Type)
VD>{
VD>  | _ when t.Equals(typeof(bool)) => ...
VD>  | _ when t.Equals(typeof(byte)) => ...
VD>  | _ when t.Equals(typeof(int))  => ...
VD>}
VD>


VD>Собсвтенно паттерн "is" как раз без проблем можно использоать:

VD>
VD>def CheckType(_ : object)
VD>{
VD>  | x is bool => // здесь x имеет тип bool
VD>  | x is byte => // здесь x имеет тип byte
VD>  | x is int  => // здесь x имеет тип int
VD>  | _         => // в ином случае ...
VD>}
VD>


действительно простота оператора is ощутима,

VD>Но зачем так извращаться когда можно просто сравнивать имя?

VD>Ведь так проще:
VD>[c#]
VD>def сheckType(t : Type)
VD>{
VD> match (t.FullName)
VD> {
VD> | "System.Bool" => WriteLine("bool");
VD> | "System.Byte" => WriteLine("byte");
VD> | "System.Int32" => WriteLine("int");
VD> | _ => WriteLine("xz")
VD> }
VD>}
Re[2]: Сопоставление match типа System.Type
От: desco США http://v2matveev.blogspot.com
Дата: 29.01.10 15:27
Оценка: 1 (1) +2
Здравствуйте, VladD2, Вы писали:

<skipped/>

в ряде случаев можно для match использовать TypeCode

        match(Type.GetTypeCode(t))
        {
            | TypeCode.Boolean => WriteLine("bool");
            | TypeCode.String => WriteLine("string");
            | _ => WriteLine("xz");
        }
Re[3]: Сопоставление match типа System.Type
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 16:55
Оценка:
Здравствуйте, CodingUnit, Вы писали:

CU>Спасибо за ответ, все таки кажется редкой такая ситуация когда могут быть загружены одинаковые типы из разных сборок, это скорее исключительная ситуация, а чаще приходится сравнивать встроенные типы, которые соответствуют одной версии типа в библиотечной сборке, может вы подскажите или дадите ссылку когда такая ситуация может встречаться, потому что на данный момент в C# только так и поступаю, сначала пробовал именно тот вариант с сравнением имени,


Достаточно загрузить две разных версии одной библиотеки. С системными типами это сделать сложнее, а вот с типами из сборок третих лиц, без проблем. Причем загрузка может быть опосредованной (грузишь одну сборку, а она тянет вторую копию другой).

CU>но это сказывается на производительности, ведь сравнение двух строк в реальном времени не такая простая операция как сравнение двух ссылок, при том что по определению CLR ссылки Type оригинальны для каждого типа и равны для одинаковых типов. Поэтому все же вариант с when кажется более приемлемым, но прошу разъяснить ситуацию в потребности избегать сравнения ссылок через сравнение имен.


Строки сравниваются по хэш-значению. Это не так уж и медленно. Кроме того строки можно интернировать (string.Intern(), string.IsInterned()). Тогда можно будет сравнивать их адреса.

К слову, операция typeof(тип) не бесплатна. Я не проводил эксперименты, но не удивлюсь, если она окажется сопоставима по временным затратам со сравнением строк.

Если же нужна производительность любой ценой, то разумно создать собственный кэш (отображение типов на некие целые числа). Тогда сравнение типов превратится в сравнение целых.

Если сравниваются системные типы, то для них можно использовать TypeCode
Автор: desco
Дата: 29.01.10
(как правильно заметил desco).

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

Так что лучше опиши задачу (исходную, а не текущее решение), а мы подскажем как ее лучше всего решить на Немерле.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Сопоставление match типа System.Type
От: nikov США http://www.linkedin.com/in/nikov
Дата: 29.01.10 18:17
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Строки сравниваются по хэш-значению.


Что ты имеешь в виду?
Re[5]: Сопоставление match типа System.Type
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.01.10 18:42
Оценка:
Здравствуйте, nikov, Вы писали:

VD>>Строки сравниваются по хэш-значению.


N>Что ты имеешь в виду?


Всякие switch("строка")/match("строка") переписываются в код вроде hashTbl("строка"). Ну, а там или число некое получается (номер слота для перехода), или еще что.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.