简体   繁体   中英

Generic Type parameter and the dynamic type

I want to know, in the example below, is the if statement in TrickyGenericMethod is a bad idea or if in certain situations it would be ok. In my case, I have a factory method, that uses the generic parameter to produce the correct result. Unfortunately, if the type reference of the object that is passed in is a reference to an interface or an abstract class, it will produce an incorrect result because T is not the actual type of the object.

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(); ;
    }
}

is the if statement in TrickyGenericMethod is a bad idea

Yes, it looks like it to me. In particular, if you call this from a different assembly using a value of an internal type (and it goes through this path once), the "execution time compiler" will use the best accessible type for the dynamic call... so you'll end up with a stack overflow.

EDIT: Sample code for that...

// 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());
    }
}

Result:

System.Object : Internal
System.Object : Internal
...
System.Object : Internal

Process is terminated due to StackOverflowException.

There may be other similar situations where it doesn't quite work, too. I would try to avoid relying on typeof(T) == value.GetType() as far as possible.

You could unconditionally call a private implementation method using dynamic typing, so that you end up only trying this once, and ending up with "best effort" approach.

1st, it's a bad idea because you are using recursion in an unnecessary way, you have at most one other call so why make it recursive, a private helper method would be more clear and less error prone as a general practice.

2nd, you are testing for when T is going to be equal to GetType() and recursing until it is, thus just use the result of GetType() directly and be done with it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM