具有显式泛型类型行为的奇怪泛型方法调用

时间:2014-12-30 12:06:46

标签: c# generics generic-method

我有一个非泛型类,带有泛型方法。此方法的泛型类型定义输出类型,不能从用法推断,因此我必须显式提供泛型类型。有时这种类型是从泛型调用者的方法类型参数传递的,但在一个实例中我必须自己明确地提供它。

问题是当我调用我明确提供的泛型类型方法调用时,似乎它没有被执行并返回一个完全无关的类型。我无法调试此调用并获得无效结果。但它并没有打破特别奇怪的执行。当从调用者的泛型方法类型传递泛型类型的其他地方调用相同的方法时,一切似乎都按照定义工作。

我完全迷失了正在发生的事情。

我在接口中的方法定义(稍后在类中实现):

TRecord Update<TRecord>(int recordId, int? categoryId, string categoryName, string title)
    where TRecord : Record;

我的Record类是非抽象的,并且只有一种类型继承自它:

public class Record : ProtectedEntity
{
    ...
}

public class RelatedRecord<T> : Record
{
    public IList<T> Related { get; private set; }
    ...
}

我正在调用我的方法:

var record = myRepo.Update<Record>(...);

当执行到达此行时,我按 F11 调试它,但执行只是跳转到下一句。当我检查我的record变量时,它不是Record类型,而是System.String,具有参数categoryName的值。这意味着某些东西会被执行,但它绝对不是我的泛型方法的主体。

奇怪的是,在其他任何地方,同一个呼叫都按预期工作。

如何解释这个问题以及我做错了什么?

2 个答案:

答案 0 :(得分:2)

根据您的意见,包括评论:

  

如果我在运行时尝试访问任何成员,它当然会抛出有关非现有成员的异常。

这听起来像编译器错误或JIT错误。这意味着要对其进行诊断,我们需要您更多地了解您正在使用的编译器(确切版本)和/或您正在使用的JIT。在编译器错误的情况下,如果您只是简单地显示已生成的IL,那么可能就足够了。

请注意,最新的VS预览包括一个全新的JIT(RyuJIT),而默认在系统范围内启用它,所以如果您已经安装了VS预览,那将是我的猜测。如果是这样,您可以轻松地将其禁用以进行检查。


请注意,此处的其他选项类似于using别名,将Record别名为System.String,或将var别名为System.String(加上一些隐式转换运算符等)。这些不太可能,但我已经看到它发生了; p

编辑:您的评论排除了上述内容:

  

执行typeof(Record).FullName正确返回我的完整类型名称,包括命名空间。

所以我们留下了编译器错误或JIT错误。


如果这是一个RyuJIT错误,这里有禁用它的选项(我建议首先使用配置,因为这是最容易做到的):

  1. 作为环境变量:设置COMPLUS_useLegacyJit = 1

  2. 在注册表中:设置HKLM或HKCU,Software \ Microsoft.NETFramework。键名:useLegacyJit。键入:REG_DWORD。价值:1

  3. 在app.exe.config文件中:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <runtime>
        <useLegacyJit enabled="1" />
      </runtime>
    </configuration>
    
  4. (这些来自我以前与MS的单独讨论)

答案 1 :(得分:1)

如果您没有收到运行时类型异常,我可能会怀疑我遇到的Visual Studio调试器中存在错误。如果在同一方法中有两个具有相同名称的本地范围变量,则调试器可能会混淆它们:

private void DoSomething(int x)
{
    {
        var s = "STRING!";
        Console.WriteLine(s);
    }
    {
        var s = 5;
        Console.WriteLine(s);
    }
}

我不知道上面的例子是否真的会重现这个问题,但是我看到了调试器的行为,你鼠标悬停在第二个s上,它显示为“STRING!”,而不是5.这将是我要检查的第一件事是,你在同一个名为“record”的方法中没有另一个局部变量。