Tidbits

My method for static methods on generic type parameters

Sorry to disappoint the people most likely to stumble upon this, I have no fancy method for providing real static methods in a generic context.
Short version:

  • Find the method through reflection
  • Compile into a Func
  • Store in generic base class

The idea is to call a method from a base class, which redirects the call to the intended method.


Let me give you an example right away, below it you’ll find the explanation:

public abstract class Parent<Twhere T : Parent<T>
{
    //Since this is a generic class, we'll have one Func for each T
    private static readonly Func<stringint> ChildGetCount;
 
    static Parent()
    {
        //Find the method
        Type[] types = { typeof(string) };
        MethodInfo methodInfo = typeof(T).GetMethod
        (
            nameof(GetCount), 
            BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly, 
            null, 
            types, 
            Array.Empty<ParameterModifier>()
        );
 
        //Verify the method exists and throw a dedicated exception if it doesn't (to make debugging easier)
        if (methodInfo is null)
            throw new MissingMethodException(typeof(T).FullName, nameof(GetCount));
 
        //Build an Expression to speed up performance
        ParameterExpression parameterExpression = Expression.Parameter(types[0]);
        MethodCallExpression methodCallExpression = Expression.Call(methodInfo, parameterExpression);
        Expression<Func<stringint>> expression = Expression.Lambda<Func<stringint>>
        (
            methodCallExpression, 
            parameterExpression
        );
 
        //Store the Func for later use
        ChildGetCount = expression.Compile();
    }
 
    public static int GetCount(string value) => ChildGetCount(value);
}
 
public class ChildA : Parent<ChildA>
{
    private new static int GetCount(string value) => value.Count(c => c == 'a');
}
 
public class ChildB : Parent<ChildB>
{
    private new static int GetCount(string value) => value.Count(c => c == 'b');
}
 
public class ChildC : Parent<ChildC>
{
    private new static int GetCount(string value) => value.Count(c => c == 'c');
}

One of the most important parts of this whole thing is the generic base class that is constrained to itself.
This way, due to the way generics work, we can force a unique parent class for each child type. And each of those parents will have the information about what exact type the child is.
By using reflection, we can now search for a specific method in that child type, and store a reference to it in the childs unique parent.
To improve performance I use System.Linq.Expression to compile the MethodInfo into a Func, but that’s not necessary to make all of this work.
Finally, we add a static method in the parent, which simply redirects the call to the stored Func.
Another unnecessary detail: I used the same name for the method in the parent and child classes.
This was mostly for cohesion, but needing the new keyword is also a good reminder that you have or haven’t “overridden” the required method yet.


With the code above we can now do this:

const string value = "a ab abc";
 
int countA = ChildA.GetCount(value);//3
int countB = ChildB.GetCount(value);//2
int countC = ChildC.GetCount(value);//1

Which we could have done with plain static methods too, of course. But we can also do this:

const string value = "a ab abc";
 
int genericCountA = Parent<ChildA>.GetCount(value);//3
int genericCountB = Parent<ChildB>.GetCount(value);//2
int genericCountC = Parent<ChildC>.GetCount(value);//1

Which finally allows for things like these, which were the whole reason I needed all of this in the first place:

public static int GenericGetCount<T>(string valuewhere T : Parent<T>
    => Parent<T>.GetCount(value);
const string value = "a ab abc";
 
int genericCountA = GenericGetCount<ChildA>(value);//3
int genericCountB = GenericGetCount<ChildB>(value);//2
int genericCountC = GenericGetCount<ChildC>(value);//1

Downsides to this approach:

First of all, this needs a very specific generic structure. Which can not always be done, mostly because you might already use generics for other reasons. At least not without some additional complications.

Secondly, the compiler doesn’t verify anything. You can add additional checks in the static initializer, and a simple test framework can verify if all children are working correctly. But it’s still noway near the level of compiler enforced security that you get with proper inheritance. It also requires more awareness on the side of the developer, making it less comfortable to work with.

Lastly, the performance impact isn’t something you should blindly ignore. Reflection is still relatively costly. And the generic base class means we have a lot of additional classes once compiled (one for each child). Nothing too disruptive, but certainly something to keep in mind.