Лямбда-выражение для свойства класса

, Так как статический метод не имеет никакого связанного объекта, , синхронизируемое ключевое слово соединит класс вместо объекта?

Да.:)

7
задан Ikarii Warrior 7 August 2009 в 00:00
поделиться

4 ответа

Вы позволяете компилятору определять параметры типа. Это отлично работает для случая 1:

class SomeClass<T> where T : class {
    void SomeMethod<TProperty>( Expression<Func<T,TProperty>> expression ){ ... }
}

, потому что вы сначала объявляете экземпляр:

var sc = new SomeClass<MyDateClass>();

, который сообщает компилятору, что T является MyDateClass . Затем, когда вы вызываете метод:

sc.SomeMethod( dt => dt.Year );

, компилятор знает, что T является MyDateClass , поэтому T.Year должен быть int. Этого достаточно, чтобы разрешить SomeMethod как SomeMethod .

Однако во втором примере явно указываются параметры типа, сообщая компилятору , а не сделать вывод:

sc.SomeMethod<MyDateClass>( dt => dt.Year );

К сожалению, он пытается вызвать SomeMethod только с одним параметром типа (бит ). Поскольку этого не существует, это ' Я пожалуюсь и скажу, что вам нужно 2 параметра типа.

Если бы вместо этого вы назвали его, как в первом примере:

sc.SomeMethod( dt => dt.Year );

Компилятор пожалуется, сообщив вам, что он не может вывести параметры типа - просто недостаточно информации, чтобы определить, что dt есть. Таким образом, вы можете явно указать оба параметра типа :

sc.SomeMethod<MyDateClass, int>( dt => dt.Year );

Или сообщить компилятору, что такое dt (что вы и сделали в первом примере, добавив SomeClass < MyDateClass> ):

sc.SomeMethod((MyDateClass dt) => dt.Year );

Изменения и обновления:

Насколько эффективно компилятор творит чудеса в первом примере? Сделать предположение, что TProperty должен быть int, потому что .Year - это int? Это ответит на мой вопрос, хотя не могу сказать, что это удовлетворительно.

Не совсем волшебство, но серия маленьких шагов. Чтобы проиллюстрировать:

  1. sc имеет тип SomeClass , в результате чего T = MyDateClass
  2. SomeMethod вызывается с параметром dt => dt.Year .
  3. dt должен быть T (так определяется SomeMethod ), который должен быть MyDateClass для экземпляра ] sc .
  4. dt.Year должен быть int, поскольку MyDateClass.Year объявлен как int.
  5. Поскольку dt => dt. Год будет всегда возвращать int, возврат выражения должен быть int. Следовательно, TProperty = int .
  6. Это превращает параметр выражение в SomeMethod , Expression > .

[B] Но какая разница между указанием T на уровне класса и указанием на уровне метода? SomeClass vs. SomeMethod ... в обоих случаях T известно, не так ли?

Да, T известен в обоих случаях. Проблема в том, что SomeMethod вызывает метод только с одним параметром типа. В примере 2 имеется 2 параметров типа. Вы можете либо заставить компилятор вывести все параметры типа для метода, либо ни одного из них. Вы не можете просто передать 1 и сделать вывод о другом ( TProperty ). Итак, если вы собираетесь явно указать T , вы также должны явно указать TProperty .

7
ответ дан 7 December 2019 в 03:18
поделиться

Вместо того, чтобы вводить подробности, ознакомьтесь с этим сообщением Эрика Липперта . Я думаю, он ответит на то, что вы пытаетесь спросить.

Я понимаю, что он длинный и надуманный, но я думаю, что это лучший ответ на ваш вопрос.

1
ответ дан 7 December 2019 в 03:18
поделиться

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

//Example 1  
class SomeClass<T> where T : class
{
  public void SomeMethod<TProperty>(Expression<Func<T,TProperty>> expression) {}
}

Кроме того, оба ваших примера «игнорируют» (то есть делают вывод) фактический тип TProperty в вашем вызове SomeMethod . Во втором примере явно указан тип T , да, но не TProperty .

В первом примере также не установлено неявной связи. Когда вы создаете экземпляр SomeClass <> с помощью T = MyDateClass , сигнатура SomeMethod для этого экземпляра фактически становится:

void SomeMethod<TProperty>(Expression<Func<MyDateClass, TProperty>> expression)

Таким образом, тип аргумента лямбда известно на данный момент, поэтому вам не нужно его указывать. Тип возврата лямбда-выражения выводится как тип выражения справа от => , и это будет выводимый тип TProperty .

Во втором примере, поскольку T не был явно указан при создании экземпляра класса, и поскольку нет способа вывести его из аргументов метода, он должен быть указан явно. После его указания TProperty выводится точно так же, как в примере №1.

сигнатура SomeMethod для этого экземпляра фактически становится:

void SomeMethod<TProperty>(Expression<Func<MyDateClass, TProperty>> expression)

Таким образом, тип аргумента лямбды известен на данный момент, поэтому вам не нужно его указывать. Тип возврата лямбда-выражения выводится как тип выражения справа от => , и это будет выводимый тип TProperty .

Во втором примере, поскольку T не был явно указан при создании экземпляра класса, и поскольку нет способа вывести его из аргументов метода, он должен быть указан явно. После его указания TProperty выводится точно так же, как в примере №1.

сигнатура SomeMethod для этого экземпляра фактически становится:

void SomeMethod<TProperty>(Expression<Func<MyDateClass, TProperty>> expression)

Итак, тип аргумента лямбды известен на данный момент, поэтому вам не нужно его указывать. Тип возврата лямбда-выражения выводится как тип выражения справа от => , и это будет выводимый тип TProperty .

Во втором примере, поскольку T не был явно указан при создании экземпляра класса, и поскольку нет способа вывести его из аргументов метода, он должен быть указан явно. После его указания TProperty выводится точно так же, как в примере №1.

не нужно это указывать. Тип возврата лямбда-выражения выводится как тип выражения справа от => , и это будет выводимый тип TProperty .

Во втором примере, поскольку T не был явно указан при создании экземпляра класса, и поскольку нет способа вывести его из аргументов метода, он должен быть указан явно. После его указания TProperty выводится точно так же, как в примере №1.

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

Во втором примере, поскольку T не был явно указан при создании экземпляра класса, и поскольку нет способа вывести его из аргументов метода, он должен быть указан явно. После его указания TProperty выводится точно так же, как в примере №1.

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

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

1
ответ дан 7 December 2019 в 03:18
поделиться

Проблема, насколько я понимаю, в просто то, что DateTime не является классом ... вы передаете в T как DateTime (явное или неявное).

Это вероятно также немного сбивает с толку то, что в первом примере у вас есть два параметра типа с именем T - один для типа, а другой для метода. На самом деле они полностью разделены ... чтобы быть одинаковыми, перепишите первый пример как:

//Example 1  
class SomeClass<T> where T : class
{
    void SomeMethod<TProperty>( Expression<Func<T,TProperty>> expression ){ ... }
}

Теперь это то же самое T: class

0
ответ дан 7 December 2019 в 03:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: