Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic static class - retrieving object type in run-time

I have an object of type X, which I can (obviously) retrieve in runtime.

var type = myObject.GetType();

And I have a generic static class.

public static class MyStaticClass<T>
{
    public static void DoStuff(T something)
    {
        // bla bla
    }
}

What I'd like to do is:

MyStaticClass<myObject.GetType()>.DoStuff(myObject);

But I can't.

In fact, there is just a few types on which MyStaticClass would operate, and they share several interfaces. One workaround is to write:

if (myObject.GetType() == typeof(X))
{
    MyStaticClass<X>.DoStuff(myObject as X);
}
if (myObject.GetType() == typeof(Y))
{
    MyStaticClass<Y>.DoStuff(myObject as Y);
}

but it's verbose, and writing that everywhere is really ugly - I feel that I shouldn't do that but also that I shouldn't have to do that.

I can't believe there is no solution. Or any neater workaround at least? Or is my approach wrong to start with (what's the alternative if so)? Should I create some (abstract?) base class for X, Y, Z?

like image 224
Konrad Morawski Avatar asked Aug 18 '26 23:08

Konrad Morawski


1 Answers

You can do this with reflection, using Type.MakeGenericType - but then you'll also need to use reflection to invoke the method. That's a bit of a pain though.

If you're using C# 4 you could use dynamic typing and type inference - although that only works for generic methods rather than generic types, so you'd need to use:

public void DoStuffDynamic(dynamic item)
{
    DoStuffHelper(item);
}

private static void DoStuffHelper<T>(T item)
{
    MyClass<T>.DoStuff(item);
}

EDIT: For performance, you can avoid doing too much actual reflection. You can perform reflection once per item type, create a delegate of the form Action<object>, and cache it in a dictionary. This can be far faster than performing reflection on every execution.

Here's a short but complete sample:

using System;
using System.Collections.Generic;
using System.Reflection;

public static class MyStaticClass
{
    private static readonly object mapLock = new object();

    private static readonly Dictionary<Type, Action<object>>
        typeActionMap = new Dictionary<Type, Action<object>>();

    private static readonly MethodInfo helperMethod =
        typeof(MyStaticClass).GetMethod("ActionHelper",
                                        BindingFlags.Static |
                                        BindingFlags.NonPublic);

    public static void DoStuffDynamic(object item)
    {
        if (item == null)
        {
            throw new ArgumentNullException("item");
        }

        Type type = item.GetType();
        Action<object> action;
        lock (mapLock)
        {
            if (!typeActionMap.TryGetValue(type, out action))
            {
                action = BuildAction(type);
                typeActionMap[type] = action;
            }
        }
        action(item);
    }

    private static Action<object> BuildAction(Type type)
    {
        MethodInfo generic = helperMethod.MakeGenericMethod(type);
        Delegate d = Delegate.CreateDelegate(typeof(Action<object>),
                                             generic);
        return (Action<object>) d;
    }

    private static void ActionHelper<T>(object item)
    {
        MyStaticClass<T>.DoStuff((T) item);
    }
}


public static class MyStaticClass<T>
{
    public static void DoStuff(T something)
    {
        Console.WriteLine("DoStuff in MyStaticClass<{0}>",
                          typeof(T));
    }
}

public class Test
{
    static void Main()
    {
        MyStaticClass.DoStuffDynamic("Hello");
        MyStaticClass.DoStuffDynamic(10);        
    }
}

I only use this sort of thing when I have to, but occasionally there really isn't any sensible alternative.

like image 101
Jon Skeet Avatar answered Aug 20 '26 14:08

Jon Skeet