I have an API which includes some methods that take in a type parameter. I am now converting them to generic methods as part of improving the API (more type-safe), while keeping the non-generic version around for backward compatibility.
Current – to be obsoleted:
public object MyMethod(object value, Type expectedType)
New:
public T MyMethod<T>(object value)
However, Mymethod calls a private helper method which also takes in a type parameter:
private object HelperMethod(object value, Type expectedType)
Question: should I also make this private helper method generic?
I have my own answer below, but I would like to know if I’m missing something. I appreciate your insights very much.
My answer is no, I should not make this private method generic.
Reason 1: this helper method is private, so even if I made it generic, it doesn’t improve the API.
Reason 2: If I make it generic, then the non-generic public methods will have to use reflection to pass the type parameter to this generic method, which means more overhead.
Making your private helper method generic does improve the API by carrying the generic type-specificity all the way through your implementation. Your implementation isn’t fully realizing the type safety benefits of generics if you throttle the type down to a core that juggles typeless System.Objects around.
For example, why is the parameter to MyMethod still a System.Object? If that parameter originates in source, chances are good that it should be a type parameter too. If the parameter originates in data, you’re probably better off with System.Object. Generics are most useful when they are used with source code, because source code expressions implicitly provide the type in most contexts.
The hidden costs of generics depends on the mix of types that will be used with the API. If most of the types will be value types (built-ins and structs), then switching the API to generics could raise your memory consumption because the generic code must be jit’d differently for each value type. If the majority of types used with your generic API are reference types (classes and interfaces), code/memory explosion isn’t a concern because all reference types share the same JIT’d code.
Whether the cost of having the old API call the new generic API is a) measurable and b) acceptable depends entirely upon what you’re doing in your private helper method – in particular, what the private helper method does with the Type parameter.
If the helper method implementation is fairly lightweight and you determine (by performance measurements) that the cost of adapting the old API to call the new generic helper is unacceptable, I would consider duplicating the helper method implementation, side by side, one in the old style and one in the new generic style. This eliminates crossover conversion costs between the API styles and eliminates the risk of introducing new bugs into the old API, at the cost of slightly increased internal code maintenance efforts.