【问题标题】:typeof this in virtual methods called from derived class从派生类调用的虚拟方法中的 typeof this
【发布时间】:2012-05-02 12:50:42
【问题描述】:

我发现自己的情况是,我在基类上有一个方法,该方法调用一个泛型方法,将自身作为参数传递(通过this)。在泛型方法中,类型始终是基类型,即使我从派生类调用方法。

我需要泛型方法知道它是派生类型而不是基类型。

我无法更改通用方法,因为它来自第三方应用程序(http://razorengine.codeplex.com/ - Razor.Parse 方法)。

我发现,如果我将该方法定义为仅限于从我的基类继承的类型的通用扩展方法,那么调用它就会起作用,但是为此目的使用扩展方法似乎很麻烦(尽管如果这是正确的用法,我'我很高兴听到这个消息)。我想知道是否有一些技巧可以在调用之前将“this”转换为派生对象的类型(可能仍然使用泛型)。

我在下面包含了一个应该是自包含的简化程序(为了个人方便,我在 LINQPad 中运行它)。本质上,我想要一个在A 上定义的方法,当在B 的实例上调用时,它将调用Test.WhatType 并输出“B”。

我希望这是有道理的。

void Main()
{
    var bar = new B();
    bar.myGetType();
    bar.ExtGetType();
}

class A
{
    public virtual void myGetType()
    {
        Test.WhatType(this);
        this.ExtGetType();
    }
}

class B : A {}

static class ext
{
    public static void ExtGetType<T>(this T obj) where T : A
    {
        Test.WhatType(obj);
    }
}

class Test
{
    public static void WhatType<T>(T obj)
    {
        Console.WriteLine(typeof(T).Name);
    }
}

编辑:将方法名称更改为A.myGetType(),因为我什至没有注意到我意外重载。

注意运行此代码输出:

A
A
B

【问题讨论】:

  • 如果你的泛型方法关心类型,过去where T : A,那么你需要重新评估那个方法。
  • 嗯,有点对 - 调用代码是 A 类! (我知道这没有帮助)我会挖掘并尝试回复你!
  • 您将不得不在 WhatType 方法中使用 obj.GetType()。
  • 此外,GetType 是一种未标记为虚拟对象的方法。请不要尝试覆盖它。

标签: c# .net generics virtual-functions


【解决方案1】:

您需要使用obj.GetType()。 T 在编译时绑定,而不是在运行时绑定,因此 typeof(T) 返回 T 的编译时类型。

【讨论】:

  • 啊。是的,所以我的测试看起来是错误的。 Test.WhatType 旨在模拟第三方应用程序中的静态方法,似乎将传递的参数视为基类。看起来我的问题实际上可能与 RazorEngine 库有关。我去那里看看。谢谢您的帮助。 :)
  • 事实上我现在发现我调用的Razor.Parse 方法确实似乎在内部使用typeof(T) 而不是mode.GetType()。我想我会去抱怨他们。 ;-)
【解决方案2】:

如果我理解正确,您的问题是A.GetType() 绑定到WhatType&lt;A&gt;,因为这就是它所知道的全部内容。

所以你必须让A 类知道派生类。

您可以使用自引用泛型类型来做到这一点。比如:

class A<T> where T : A<T>
{
    public virtual void GetType()
    {
        Test.WhatType<T>( (T) this );
    }
}

class B : A<B> { }

然后:

new B().GetType();

将绑定到WhatType&lt;B&gt;,因此将输出B

【讨论】:

  • 啊,这就是我想知道的事情。我现在不确定我是否将其视为一种解决方案,但是否更整洁,但感谢您的分享。这看起来肯定很有用。 :)
  • 从A.GetType() 内部调用扩展方法输出A - 我以为你希望它输出B?
  • 我不确定我是否理解您的后续问题。
  • ok :) Main 调用 bar.myGetType(),后者又调用 this.ExtGetType(),编译器将其解析为 ExtGetType&lt;A&gt;,因此输出 A - 示例输出中的第二个 A。我以为你希望它输出 B?
  • 我现在已将正确答案更改为这个,因为虽然另一个对我的帮助更大,但它没有直接回答如何使静态方法输出 B 的问题。这个答案是这样做的实际上是正确的。 :)
【解决方案3】:

此方法返回静态类型(T)的类型。它应该被实现为

public static void WhatType<T>(T obj) 
{ 
    Console.WriteLine(obj.GetType().Name); 
} 

编辑: 我刚刚意识到您想要的是以通用方法的 T 更改的方式操作 A 。您可以通过反射或添加基于 A 的子类型的 switch 语句并将其显式转换为 B(或任何类)来执行此操作。当然,这些解决方案都不好,因为 A 会依赖于它的子类和反射显然是 sux。另一种选择是覆盖每个子类中的 GetType() 方法,从而将责任转移到子类。

【讨论】:

  • typeof 需要一个类型。我想你的意思是 obj.GetType()
  • 这永远不会编译。 obj 不是 typeof 的有效参数。它需要一个类型名称。
  • 注意,而不是批评您的答案:这只会起作用,因为您/OP 没有将 where T : A 放入。如果您添加它,则将使用 A.GetType()而不是Object.GetType()。 (A.GetType 的名字很糟糕。)
  • 是的,事实上它会产生一个警告,因为 A.GetType 隐藏了 Object.GetType(并且没有“new”关键字)。
  • @hvd:这只是我的一些非常糟糕的命名。 A.GetType 现在已更改为 A.myGetType 以区分它。感谢您的观察。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-14
  • 2020-10-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多