, Так как статический метод не имеет никакого связанного объекта, , синхронизируемое ключевое слово соединит класс вместо объекта?
Да.:)
Вы позволяете компилятору определять параметры типа. Это отлично работает для случая 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? Это ответит на мой вопрос, хотя не могу сказать, что это удовлетворительно.
Не совсем волшебство, но серия маленьких шагов. Чтобы проиллюстрировать:
sc
имеет тип SomeClass
, в результате чего T = MyDateClass
SomeMethod
вызывается с параметром dt => dt.Year
. dt
должен быть T (так определяется SomeMethod
), который должен быть MyDateClass
для экземпляра ] sc
. dt.Year
должен быть int, поскольку MyDateClass.Year
объявлен как int. dt => dt. Год
будет всегда возвращать int, возврат выражения
должен быть int. Следовательно, TProperty = int
. выражение
в SomeMethod
, Expression >
.
[B] Но какая разница между указанием T на уровне класса и указанием на уровне метода?
SomeClass
vs.SomeMethod
... в обоих случаях T известно, не так ли?
Да, T
известен в обоих случаях. Проблема в том, что SomeMethod
вызывает метод только с одним параметром типа. В примере 2 имеется 2 параметров типа. Вы можете либо заставить компилятор вывести все параметры типа для метода, либо ни одного из них. Вы не можете просто передать 1 и сделать вывод о другом ( TProperty
). Итак, если вы собираетесь явно указать T
, вы также должны явно указать TProperty
.
Вместо того, чтобы вводить подробности, ознакомьтесь с этим сообщением Эрика Липперта . Я думаю, он ответит на то, что вы пытаетесь спросить.
Я понимаю, что он длинный и надуманный, но я думаю, что это лучший ответ на ваш вопрос.
Прежде всего, ваш первый пример неверен и не будет компилироваться, как указано. Помимо отсутствующего общедоступного
в методе, вы определяете 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.
TProperty
выводится точно так же, как в примере №1. s невозможно вывести это из аргументов метода, это должно быть указано явно. После его указания TProperty
выводится точно так же, как, например, № 1. Проблема, насколько я понимаю, в просто то, что DateTime
не является классом ... вы передаете в T
как DateTime
(явное или неявное).
Это вероятно также немного сбивает с толку то, что в первом примере у вас есть два параметра типа с именем T
- один для типа, а другой для метода. На самом деле они полностью разделены ... чтобы быть одинаковыми, перепишите первый пример как:
//Example 1
class SomeClass<T> where T : class
{
void SomeMethod<TProperty>( Expression<Func<T,TProperty>> expression ){ ... }
}
Теперь это то же самое T: class