Calling a static method on a generic type parameter

C#Generics

C# Problem Overview


I was hoping to do something like this, but it appears to be illegal in C#:

public Collection MethodThatFetchesSomething<T>()
    where T : SomeBaseClass
{
    return T.StaticMethodOnSomeBaseClassThatReturnsCollection();
}

I get a compile-time error:

> 'T' is a 'type parameter', which is not valid in the given context.

Given a generic type parameter, how can I call a static method on the generic class? The static method has to be available, given the constraint.

C# Solutions


Solution 1 - C#

In this case you should just call the static method on the constrainted type directly. C# (and the CLR) do not support virtual static methods. So:

T.StaticMethodOnSomeBaseClassThatReturnsCollection

...can be no different than:

SomeBaseClass.StaticMethodOnSomeBaseClassThatReturnsCollection

Going through the generic type parameter is an unneeded indirection and hence not supported.

Solution 2 - C#

To elaborate on a previous answer, I think reflection is closer to what you want here. I could give 1001 reasons why you should or should not do something, I'll just answer your question as asked. I think you should call the GetMethod method on the type of the generic parameter and go from there. For example, for a function:

public void doSomething<T>() where T : someParent
{
    List<T> items=(List<T>)typeof(T).GetMethod("fetchAll").Invoke(null,new object[]{});
    //do something with items
}

Where T is any class that has the static method fetchAll().

Yes, I'm aware this is horrifically slow and may crash if someParent doesn't force all of its child classes to implement fetchAll but it answers the question as asked.

Solution 3 - C#

The only way of calling such a method would be via reflection, However, it sounds like it might be possible to wrap that functionality in an interface and use an instance-based IoC / factory / etc pattern.

Solution 4 - C#

It sounds like you're trying to use generics to work around the fact that there are no "virtual static methods" in C#.

Unfortunately, that's not gonna work.

Solution 5 - C#

I just wanted to throw it out there that sometimes delegates solve these problems, depending on context.

If you need to call the static method as some kind of a factory or initialization method, then you could declare a delegate and pass the static method to the relevant generic factory or whatever it is that needs this "generic class with this static method".

For example:

class Factory<TProduct> where TProduct : new()
{
	public delegate void ProductInitializationMethod(TProduct newProduct);


	private ProductInitializationMethod m_ProductInitializationMethod;


	public Factory(ProductInitializationMethod p_ProductInitializationMethod)
	{
		m_ProductInitializationMethod = p_ProductInitializationMethod;
	}
	
	public TProduct CreateProduct()
	{
		var prod = new TProduct();
		m_ProductInitializationMethod(prod);
		return prod;
	}
}

class ProductA
{
	public static void InitializeProduct(ProductA newProduct)
	{
		// .. Do something with a new ProductA
	}
}

class ProductB
{
	public static void InitializeProduct(ProductB newProduct)
	{
		// .. Do something with a new ProductA
	}
}

class GenericAndDelegateTest
{
	public static void Main()
	{
		var factoryA = new Factory<ProductA>(ProductA.InitializeProduct);
		var factoryB = new Factory<ProductB>(ProductB.InitializeProduct);

		ProductA prodA = factoryA.CreateProduct();
		ProductB prodB = factoryB.CreateProduct();
	}
}

Unfortunately you can't enforce that the class has the right method, but you can at least compile-time-enforce that the resulting factory method has everything it expects (i.e an initialization method with exactly the right signature). This is better than a run time reflection exception.

This approach also has some benefits, i.e you can reuse init methods, have them be instance methods, etc.

Solution 6 - C#

You should be able to do this using reflection, as is described here

Due to link being dead, I found the relevant details in the wayback machine:

> Assume you have a class with a static generic method:

class ClassWithGenericStaticMethod
{
    public static void PrintName<T>(string prefix) where T : class
    {
        Console.WriteLine(prefix + " " + typeof(T).FullName);
    }
}

> How can you invoke this method using relection? > > > It turns out to be very easy… This is how you Invoke a Static Generic > Method using Reflection:

// Grabbing the type that has the static generic method
Type typeofClassWithGenericStaticMethod = typeof(ClassWithGenericStaticMethod);

// Grabbing the specific static method
MethodInfo methodInfo = typeofClassWithGenericStaticMethod.GetMethod("PrintName", System.Reflection.BindingFlags.Static | BindingFlags.Public);

// Binding the method info to generic arguments
Type[] genericArguments = new Type[] { typeof(Program) };
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(genericArguments);

// Simply invoking the method and passing parameters
// The null parameter is the object to call the method from. Since the method is
// static, pass null.
object returnValue = genericMethodInfo.Invoke(null, new object[] { "hello" });

Solution 7 - C#

You can do what I call a surrogate singleton, I've been using it as a sort of "static inheritance" for a while

interface IFoo<T> where T : IFoo<T>, new()
{
    ICollection<T> ReturnsCollection();
}

static class Foo<T> where T : IFoo<T>, new()
{
    private static readonly T value = new();
    public static ICollection<T> ReturnsCollection() => value.ReturnsCollection();
}

// Use case

public ICollection<T> DoSomething<T>() where T : IFoo<T>, new()
{
    return Foo<T>.ReturnsCollection();
}

Solution 8 - C#

As of now, you can't. You need a way of telling the compiler that T has that method, and presently, there's no way to do that. (Many are pushing Microsoft to expand what can be specified in a generic constraint, so maybe this will be possible in the future).

Solution 9 - C#

Here, i post an example that work, it's a workaround

public interface eInterface {
    void MethodOnSomeBaseClassThatReturnsCollection();
}

public T:SomeBaseClass, eInterface {

   public void MethodOnSomeBaseClassThatReturnsCollection() 
   { StaticMethodOnSomeBaseClassThatReturnsCollection() }

}

public Collection MethodThatFetchesSomething<T>() where T : SomeBaseClass, eInterface
{ 
   return ((eInterface)(new T()).StaticMethodOnSomeBaseClassThatReturnsCollection();
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRemi Despres-SmythView Question on Stackoverflow
Solution 1 - C#JaredParView Answer on Stackoverflow
Solution 2 - C#Joshua PechView Answer on Stackoverflow
Solution 3 - C#Marc GravellView Answer on Stackoverflow
Solution 4 - C#Brad WilsonView Answer on Stackoverflow
Solution 5 - C#Amir AbiriView Answer on Stackoverflow
Solution 6 - C#johncView Answer on Stackoverflow
Solution 7 - C#micahneitzView Answer on Stackoverflow
Solution 8 - C#James CurranView Answer on Stackoverflow
Solution 9 - C#rodrijpView Answer on Stackoverflow