简体   繁体   English

c#泛型函数类型不适应重载

[英]c# generic function type not adapting to overloads

I'm writing a generic function (templated function?) in unity c# and I encountered this problem.我正在统一 c# 中编写一个通用函数(模板函数?),我遇到了这个问题。 The function was ran templated with a type deriving from Component该函数是使用从Component派生的类型模板化运行的

T component = transform.gameObject.GetComponent<T>();
if(component != null)
{
    objects.Add(component);
}

I stepped through this and the value of component was "null" (which i expected) but then the program carried on and entered the if block...我逐步完成了这个,并且component的值是"null" (我期望的)但是然后程序继续并进入了if块......

In unity overloads the == / != operators to allow for null checks on their components (which are never actually null - so for example, component ??= foo should not work), but the overload of this function above should be fine when the type of T is a Component ?在统一重载== / !=运算符以允许对其组件进行空检查(它们实际上永远不会为空 - 因此,例如, component ??= foo不应该工作),但是上面这个函数的重载应该没问题T的类型是Component吗?

I eventually managed to get it working with:我最终设法让它与:

if(component as Component != null){...}

But my question is, why was this necessary?但我的问题是,为什么这是必要的? Does c# not check for operator overloads of types passed into generic functions? c# 不检查传递给泛型函数的类型的运算符重载吗? Surely the literal type passed is swapped in at runtime?传递的文字类型肯定在运行时换入吗?

You're right, the actual type argument is swapped in at runtime.你是对的,实际的类型参数是在运行时交换的。

But the operator calls are bound statically at compile time.但是操作符调用在编译时是静态绑定的。 Operators are not instance methods of types, there are static methods defined on types.运算符不是类型的实例方法,类型上定义了静态方法。 So code like this:所以代码如下:

Component a, b;

a == b

resolves to决心

Component a, b;

Component.op_Equality(a, b)

at compile time 1 .在编译时1 .

When you write a generic method without any constraints the compiler treats T as the most general type it can be: object .当您编写没有任何约束的泛型方法时,编译器将T视为最通用的类​​型,它可以是: object This allows you to use any methods that are defined on object , since any type substituted for T will have those methods.这允许您使用在object上定义的任何方法,因为替换T任何类型都将具有这些方法。 But it can't assume anything else, since it is entirely possible the user is going to actually supply object as the argument for T .但它不能假设任何其他内容,因为用户完全有可能实际提供object作为T的参数。 So code like this:所以代码如下:

Foo<T>(T a) {
  if (a == null) {
    // ... 
  }
}

has to resolve to a simple null reference check, since you can compare any object with null just by checking whether the reference equals 0 or not.必须解析为简单的空引用检查,因为您可以通过检查引用是否等于0来将任何objectnull进行比较。 It cannot resolve to它无法解决

Foo<T>(T a) {
  if (Component.op_Equality(a, null)) {
    // ...
  }
}

since at runtime you might supply object as T and pass something that is not assignable to Component to Foo .因为在运行时您可能会提供object作为T并将某些不可分配给Component传递给Foo Generic methods are compiled only once for all reference types and then reused with metadata about the actual type arguments .泛型方法只为所有引用类型编译一次,然后与有关实际类型参数的元数据一起重用

But you can help the compiler by saying但是你可以通过说帮助编译器

Foo<T>(T a) where T : Component {
  ...
}

Now you constrained possible values of T to subtypes of Component , so the compiler happily emits a call to the Component 's equality check.现在您将T可能值限制为Component子类型,因此编译器很高兴地发出对Component的相等性检查的调用。 If you add this constraint to your method it will solve your problem.如果您将此约束添加到您的方法中,它将解决您的问题。

Judging by your use of the word "template" you might have a C++ background: the important thing to note about generics is that they are very different from C++ templates, in particular, as mentioned, they are compiled once (for reference types) so the code inside them has to work with any possible value of T .从你对“模板”这个词的使用来看,你可能有 C++ 背景:关于泛型需要注意的重要一点是它们与 C++ 模板非常不同,特别是,如上所述,它们被编译一次(用于引用类型)所以其中的代码必须使用T任何可能值。 It does not recompile the code inside a generic method every time you call it (like template instantiations in C++).它不会在每次调用时重新编译泛型方法中的代码(如 C++ 中的模板实例化)。

===== ======

1 Note that the name op_Equality is not visible to the user, you can't call the method verbatim from C# code, you need to use the == operator. 1请注意,名称op_Equality对用户不可见,您不能从 C# 代码中逐字调用该方法,您需要使用==运算符。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM