泛型类型参数和动态类型

本文关键字:类型 动态 泛型类型参数 | 更新日期: 2023-09-27 18:14:10

我想知道,在下面的例子中,TrickyGenericMethod中的if语句是一个坏主意,还是在某些情况下它是可以的。在我的例子中,我有一个工厂方法,它使用泛型参数来产生正确的结果。不幸的是,如果传入的对象的类型引用是对接口或抽象类的引用,则会产生错误的结果,因为T不是对象的实际类型。

class Program
{
    static void Main(string[] args)
    {
        HasGenericMethod hgm = new HasGenericMethod();
        Console.WriteLine(hgm.GenericMehtod("string"));
        Console.WriteLine(hgm.GenericMehtod((object)"object"));
        Console.WriteLine();
        Console.WriteLine(hgm.TrickyGenericMethod("string"));
        Console.WriteLine(hgm.TrickyGenericMethod((object)"object"));

        Console.ReadKey();
    }
}
class HasGenericMethod
{
    public string GenericMehtod<T>(T param)
    {
        return  "Type of T:'t" + typeof(T) + "'tType of param:'t" + param.GetType();
    }
    public string TrickyGenericMethod<T>(T param)
    {
        if (typeof(T) != param.GetType())
        {
            return TrickyGenericMethod((dynamic)param);
        }
        return "Type of T:'t" + typeof(T) + "'tType of param:'t" + param.GetType(); ;
    }
}

泛型类型参数和动态类型

是TrickyGenericMethod中的if语句

是一个坏主意

是的,在我看来是这样。特别是,如果您使用内部类型的值从不同的程序集调用它(并且它经过此路径一次),"执行时间编译器"将使用dynamic调用的最佳可访问类型……所以你最终会得到一个堆栈溢出。

编辑:示例代码…

// Library.cs
using System;
public class Library
{
    public static void Foo<T>(T value)
    {
        Console.WriteLine("{0} : {1}", typeof(T), value.GetType());
        if (typeof(T) != value.GetType())
        {
            dynamic d = value;
            Foo(d);
        }
    }
}
// Test.cs
class Internal {}
class Program
{
    static void Main(string[] args)  
    {
        Library.Foo<object>(new Internal());
    }
}
结果:

System.Object : Internal
System.Object : Internal
...
System.Object : Internal
Process is terminated due to StackOverflowException.

可能还有其他类似的情况,它也不能完全工作。我会尽量避免依赖typeof(T) == value.GetType()

您可以无条件地使用动态类型调用私有实现方法,这样您最终只尝试一次,并以"尽力而为"的方法结束。

首先,这是一个坏主意,因为你以一种不必要的方式使用递归,你最多有一个其他调用,所以为什么要递归,一个私有的助手方法会更清晰,更少出错。

第二,您正在测试何时T将等于GetType()并递归直到它,因此只需直接使用GetType()的结果并完成它。