有人可以解释为什么以下两个示例中的第一个有效而另一个无效? 更具体地说,第一个示例中 T 和 TProperty 之间的关系是如何创建的?
//Example 1
class SomeClass<T> where T : class
{
void SomeMethod<TProperty>( Expression<Func<T,TProperty>> expression ){ ... }
}
//Example 2
class SomeClass
{
void SomeMethod<T,TProperty>( Expression<Func<T,TProperty>> expression )
where T : class{ ... }
}
鉴于这两个示例,我希望以下实现能够工作,但第二个实现不行。
//Implementation w/ Example 1
var sc = new SomeClass<MyDateClass>();
sc.SomeMethod( dt => dt.Year );
//Implementation w/ Example 2
var sc = new SomeClass();
sc.SomeMethod<MyDateClass>( dt => dt.Year );
我很难理解的是,第一个示例/实现在执行 SomeMethod 时如何忽略 TProperty 泛型类型,而第二个示例/实现却不能,以及如何在 T 和 TProperty 之间建立隐式关系示例/实现 1.
解决方案
如下更改示例 2 中方法的签名:
void SomeMethod<T>( Expression<Func<T,Object>> expression ){ ... }
虽然这将允许在表达式中使用任意对象作为结果,但它确实允许如实现 2 中所述的属性表达。
Can someone explain why the first of the two following examples is valid and the other is not? More specifically, how is a relationship created between T and TProperty in the first example?
//Example 1
class SomeClass<T> where T : class
{
void SomeMethod<TProperty>( Expression<Func<T,TProperty>> expression ){ ... }
}
//Example 2
class SomeClass
{
void SomeMethod<T,TProperty>( Expression<Func<T,TProperty>> expression )
where T : class{ ... }
}
Given the two examples I would expect that the following implementations would work, but the second one does not.
//Implementation w/ Example 1
var sc = new SomeClass<MyDateClass>();
sc.SomeMethod( dt => dt.Year );
//Implementation w/ Example 2
var sc = new SomeClass();
sc.SomeMethod<MyDateClass>( dt => dt.Year );
What I'm having difficulty wrapping my mind around is how the first example/implementation can ignore the TProperty generic type when executing SomeMethod, yet the second example/implementation can't and how an implicit relationship seems to be established between T and TProperty in example/implementation 1.
Solution
Change signature of method in example 2 as follows:
void SomeMethod<T>( Expression<Func<T,Object>> expression ){ ... }
While this will allow arbitrary objects to be used in the expression as a result it does allow for property articulation as described in implementation 2.
发布评论
评论(4)
首先,您的第一个示例不正确,并且不会按给定方式编译。 除了方法上缺少
public
之外,您还定义了两次T
- 一次在类上,一次在方法上。 这本身并不是一个错误(尽管您会收到警告),但是在编译方法调用时,您会收到与示例 #2 中描述的相同的错误。 因此,我假设实际的代码是这样的:此外,您的两个示例都“忽略”(即推断)对
SomeMethod
的调用中TProperty
的实际类型。 您的第二个示例明确指定了T
的类型,是的,但不是TProperty
。第一个示例中也没有建立隐式关系。 当您使用
T=MyDateClass
实例化SomeClass<>
时,该实例化的SomeMethod
签名实际上变为:因此 lambda 的参数类型此时已知,因此您不必指定它。 表达式 lambda 的返回类型被推断为
=>
右侧表达式的类型,这将是TProperty
的推断类型。在第二个示例中,由于在实例化类时未显式指定
T
,并且无法从方法参数推断它,因此必须显式指定它。 指定后,TProperty
将以与示例 #1 完全相同的方式推断。First of all, your first example is incorrect, and won't compile as given. Aside from the missing
public
on the method, you defineT
twice - once on class, and once on method. This isn't an error in and of itself (though you'll get a warning), but when compiling the method call, you'll get the same error as you describe getting for example #2. So, I assume the actual code is like this:Furthermore, both your examples "ignore" (that is, infer) the actual type of
TProperty
in your call toSomeMethod
. Your second example explicitly specifies the type ofT
, yes, but notTProperty
.There's no implicit relationship established in the first example, either. When you instantiate
SomeClass<>
withT=MyDateClass
, the signature ofSomeMethod
for that instantiation effectively becomes:So the argument type of the lambda is known at this point, so you don't have to specify it. The return type of expression lambda is inferred as the type of expression on the right of
=>
, and that will be the inferred type ofTProperty
.In the second example, since
T
was not explicitly specified when instantiating the class, and since there's no way to infer it from method arguments, it has to be specified explicitly. Once you specify it,TProperty
is inferred in exact same way as for example #1.您允许编译器推断类型参数。 这适用于情况 1:
因为您首先声明一个实例:
它告诉编译器 T 是 MyDateClass。 然后,当您调用该方法时:
编译器知道
T是MyDateClass
,因此T.Year
必须是int。 这些信息足以将SomeMethod
解析为SomeMethod
。然而,您的第二个示例明确声明了类型参数 - 告诉编译器不推断它:
不幸的是,它试图仅使用一个来调用
SomeMethod
类型参数(
位)。 由于它不存在,它会抱怨并说你需要 2 个类型参数。相反,如果您像第一个示例那样调用它:
编译器会抱怨,告诉您它无法推断类型参数 - 根本没有足够的信息来确定 dt 是什么。 因此,您可以显式声明两个类型参数:
或者,告诉编译器
dt
是什么(这就是您在第一个示例中通过新建SomeClass所做的事情) ;
):编辑和更新:
并不是真正的魔法,而是一系列的小步骤。 说明一下:
sc
的类型为SomeClass
,使得T = MyDateClass
SomeMethod
dt => 的 dt.年份
。dt
必须是一个T(这就是SomeMethod
的定义方式),它必须是一个MyDateClass< /code> 为实例
sc
。dt.Year
必须是一个 int,因为MyDateClass.Year
被声明为一个 int。dt => dt.Year
总是返回一个int,表达式
的返回必须是int。 因此TProperty = int
。表达式
变为SomeMethod
、Expression>
。 回想一下T = MyDateClass
(步骤 1)和TProperty = int
(步骤 5)。SomeMethod
=SomeMethod
。是的,
T
在这两种情况下都是已知的。 问题在于SomeMethod
调用仅具有单个类型参数的方法。 在示例 2 中,有 2 个类型参数。 您可以让编译器推断该方法的所有 类型参数,也可以不推断 任何类型参数。 您不能只传递 1 并让它推断另一个 (TProperty
)。 因此,如果您要显式声明T
,那么您还必须显式声明TProperty
。You're allowing the compiler to infer the type parameters. This works fine for case 1:
because you first declare an instance:
which tells the compiler that
T is MyDateClass
. Then, when you call the method:the compiler knows that
T is MyDateClass
, soT.Year
must be an int. That's enough info to resolveSomeMethod
asSomeMethod<MyDateClass, int>
.Your second example, however, is explicitly stating the type parameter(s) - telling the compiler to not infer it:
Unfortunately, it is trying to call
SomeMethod
with only a single type parameter (the<MyDateClass>
bit). Since that doesn't exist, it'll complain and say you need 2 type parameters.If, instead, you were to call it like you did the first example:
The compiler will complain, telling you that it cannot infer the type parameters - there's simply not enough info to determine what
dt
is. So, you could explicitly state both type parameters:Or, tell the compiler what
dt
is (which is what you did in the first example by newingSomeClass<MyDateClass>
):Edits and Updates:
Not really magic, but a series of small steps. To illustate:
sc
is of typeSomeClass<MyDateClass>
, makingT = MyDateClass
SomeMethod
is called with a parameter ofdt => dt.Year
.dt
must be a T (that's howSomeMethod
is defined), which must be aMyDateClass
for the instancesc
.dt.Year
must be an int, asMyDateClass.Year
is declared an int.dt => dt.Year
will always return an int, the return ofexpression
must be int. ThereforeTProperty = int
.expression
toSomeMethod
,Expression<Func<MyDateClass,int>>
. Recall thatT = MyDateClass
(step 1), andTProperty = int
(step 5).SomeMethod<T, TProperty>
=SomeMethod<MyDateClass, int>
.Yes,
T
is known in both cases. The problem is thatSomeMethod<SomeType>
calls a method with only a single type parameter. In example 2, there are 2 type parameters. You can either have the compiler infer all type parameters for the method, or none of them. You can't just pass 1 and have it infer the other (TProperty
). So, if you're going to explicitly stateT
, then you must also explicitly stateTProperty
.据我所知,问题很简单,
DateTime
不是一个类......您将T
作为DateTime
传递>(无论是隐式的还是显式的)。可能还有些令人困惑的是,在第一个示例中,您有两个名为
T
的类型参数 - 一个位于类型上,另一个位于方法上。 它们实际上是完全独立的......为了相同,将第一个示例重写为:这现在是相同的
T : class
The problem, as far as I can see, is simply that
DateTime
isn't a class... you're passing inT
asDateTime
(whether it is implicit or explicit).It is probably also slightly confusing that in the first example you have two type parameters called
T
- one on the type, and one on the method. They are actually completely separate... to be the same, rewrite the first example as:This is now the same
T : class
不要输入具体细节,请查看 埃里克·利珀特。 我想它会回答你想问的问题。
我知道它又长又做作,但我认为这是回答你的最佳选择。
Rather than typing out the specifics, please take a look at this post by Eric Lippert. I think it will answer what you're attempting to ask.
I realize it's long and contrived, but I think it's the best bang for the buck for answering you.