通用类型参数和动态类型

时间:2011-11-10 17:59:12

标签: c# generics c#-4.0 dynamic

我想知道,在下面的示例中,if中的TrickyGenericMethod语句是一个坏主意,或者在某些情况下它会没问题。在我的例子中,我有一个工厂方法,它使用泛型参数来产生正确的结果。不幸的是,如果传入的对象的类型引用是对接口或抽象类的引用,则它将产生不正确的结果,因为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(); ;
    }
}

2 个答案:

答案 0 :(得分:4)

  

是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()

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

答案 1 :(得分:0)

第一,这是一个坏主意,因为你以不必要的方式使用递归,你最多只有一个其他的调用,所以为什么要使它递归,私有帮助方法会更清晰,更不容易出错,作为一般做法。

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