【问题标题】:C# generics implementationC# 泛型实现
【发布时间】:2017-10-31 22:44:18
【问题描述】:

我是 C# 新手,周末尝试编写 SNTP 服务器。 在此开发过程中,我最终遇到了与此完全相同的问题:How to use generics to pass argument to a non-generic method?

这里重复的问题是:“如何使用泛型将参数传递给非泛型方法?”这个问题的关键答案是所讨论的非泛型方法没有接受对象的重载。

现在我的问题是一个后续问题:为什么泛型以这种方式实现?或者换句话说,为什么需要约束?

到目前为止,我的理解是泛型有助于保持编译时类型安全,这意味着编译器知道在编译时正在处理哪些类型。

为什么没有实现 C#(或者这个问题应该与 CLR 相关),以便编译器可以接受这样一个事实,即正在创建一个泛型类/方法,其中可以提供一个在所有情况。然后,当调用泛型类/方法时,编译器可以看到问题并抱怨当时

这是技术限制吗?

似乎真的很遗憾,不能创建泛型方法来包装具有多个重载的非泛型方法。除非我选择将类型检查推迟到运行时,这是上述问题的解决方案,否则我将不得不用一套方法包装这个重载方法,每个签名一个,即使其中的代码看起来相同。这将是利用泛型方法的理想场所。

【问题讨论】:

  • 那时就不是泛型了,而是动态类型。你会得到一个运行时错误。正是您不想想要发生的事情。您希望 编译器 告诉您您传递了错误的类型,以便您可以修复它。顺便说一句,您可以使用 dynamic 作为泛型类型,失去所有类型检查的好处
  • 听起来你在描述dynamicdynamic 变量像泛型一样被类型检查,但在运行时,而不是编译时。你可能会做出这样的选择是有原因的。但是编译时安全是一个相当有用的工具。与所有事情一样,您根据所涉及的权衡做出选择。
  • 不,我的问题与为什么编译器在调用相关泛型时不能静态确保类型兼容性,而不是通过约束来确保这一点(或者在我的情况下,“计算机说不”场景)。
  • dynamic 就是这样做的。它在调用方法时检查类型,如果没有则抛出异常。
  • 对于泛型,答案通常是“考虑到泛型类型T 可能既是值类型又是引用类型,并且我们必须提前知道生成/调用正确的通用实现”?编译器不愿意插入修正代码来使这种情况正常工作,因为 C# 设计者更喜欢“所见即所得”的方法来处理这些事情。

标签: c# generic-programming


【解决方案1】:

最能解释这一点的人是 Eric Lippert,他做到了,What’s the difference, part one: Generics are not templates

我们执行一次重载解析并烘焙结果。当某人(可能在完全不同的程序集中)使用字符串作为方法的类型参数时,我们不会在运行时更改它。我们为泛型类型生成的 IL 已经选择了它要调用的方法。抖动并不是说“好吧,我碰巧知道,如果我们要求 C# 编译器立即使用这些附加信息执行,那么它会选择不同的重载。让我重写生成的代码,忽略C#编译器最初生成的代码……” jitter对C#的规则一无所知。

[...]

现在,如果您确实希望根据参数的运行时类型在运行时重新执行重载决议,我们可以为您做到;这就是 C# 4.0 中新的“动态”特性所做的。只需将“object”替换为“dynamic”,当您进行涉及该对象的调用时,我们将在运行时运行重载解析算法并动态吐出调用编译器将选择的方法的代码,如果它知道所有运行时编译时的类型。

为什么不呢:因为运行时不知道如何重新生成所需的代码。

还有一些关于设计理念的东西,即您的代码应该尽早失败,最好是在编译期间,但我现在找不到那句话。

【讨论】:

  • 好吧,这更有意义。只是为了澄清我的理解,假设在我使用 generic_method 和 generic_method 的情况下,编译器为什么不能在我在代码中调用它们的两个版本的 generic_method 中烘焙?还是我对模板的想法太多了?
  • 因为编译器会在编译时解决最佳重载问题。运行时只是运行代码,它不会事后猜测编译器并在运行时选择另一个重载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多