Using the generic type argument instead of the System.Type type argument. Is that a smell?

I often see (in many mocking libraries, for example) methods where instead of an argument of type System.Type , an argument of a universal type is used. I specifically talk about cases when the generic type is used only in the typeof(T) operation (i.e., no instance of type T is used anywhere in the method, and T is not used for the return type or for other arguments).

For example, consider the following method:

 public string GetTypeName(System.Type type) { return type.FullName; } 

this method is often accompanied by a general version:

 public string GetTypeName<T>() { return GetTypeName(typeof(T)); } 

Questions is bad practice or good practice?
Is it syntactic sugar or is there more?

I see this as a misuse of a language function to reduce the invocation of a method that takes an argument of type System.Type

Would you consider this smell? Should this be avoided? or it’s really good practice (provide a generic method as a shortcut to avoid typing typeof() ).

Here are some practical problems using this pattern that I can think of:

  • If an argument of type non System.Type is added - the method may need to be rewritten (if the order of the arguments is semantically significant) for the non-general version (otherwise some arguments will be arguments of a general type, and some will be regular arguments).
  • this requires two methods (common and not common for cases when the type is unknown at compile time). Consequently, it adds unit tests, which are basically pointless.

On the other hand, this is common practice (and most are always right, right?), But more importantly, ReSharper prefers this signature when I refactor the Extract Method on code that requires a single argument of the System.Type type known during compilation ( and I learned to take their recommendations, although not by faith, but seriously).

+13
c # coding-style code-smell
Aug 15 '13 at 16:21
source share
6 answers

I think you need to consider the documentation. How obvious are the methods doing? If you have two methods (one with Type and one with a type argument), users should look at both and choose. People who don’t look at your code may not understand that the second simply calls the first.

If it definitely makes sense to use both, this is when the type argument is actually used, when it can be, and there is some kind of rollback for the Type version. For example:

 object GetThingOfType(Type type) { ... } T GetThingOfType<T>() { return (T)GetThingOfType(typeof(T)); } 

Another thing to consider: a type argument must always be explicitly written. If it is likely that several operations will be performed on the same type object, it is impractical to use type arguments. Consider something like this:

 var t = typeof(string); var name = GetTypeName(t); var assemblyName = t.Assembly.FullName; 

Even if I know that the type is string , I should not write GetTypeName<string> here, because I will repeat it myself. By giving me the option that I most often prefer not to choose, you add a little unnecessary complexity.

A more obscure point is the support for the XML document in the IDE. You document the type argument as follows:

 <typeparam name="T">important information</typeparam> 

Then, if you type GetTypeName< in C #, Visual Studio will display “T: Important Information”. But for some reason, when you type GetTypeName(Of in Visual Basic, it will not (starting in 2012).

+3
Oct. 16 '13 at 15:13
source share

You are right: consider the semantics of the method. Does it work on type instances or on the type itself?

If it works with instances, then this should be a general method. If it belongs to a type, make it an argument of type Type .

So in your example, I would say

 public string GetTypeName(System.Type type) { return type.FullName; } 

While

 public static int Count<TSource>(this IEnumerable<TSource> source) 

Powered by an instance of source type IEnumerable<TSource> .

In general, I saw how generics abuse more than well-used ones. Any implementation of a generic method that makes typeof (T) or worse uses any reflection, in my opinion, is not generic and is an abuse. After all, generic means that it works the same regardless of the type argument, right?

So, in general, I agree with you - it smells.

+3
Oct. 16 '13 at 16:58
source share

I do not use the string GetName<T>() { return typeof(T).Name; } template string GetName<T>() { return typeof(T).Name; } string GetName<T>() { return typeof(T).Name; } , since this is a misuse (misuse is probably strong, but I can’t think of the right word) for a design pattern that is the cause of generics, namely: type parameters exist for the compiler and JITter (see the answer to this question ), so that they can create type storage, parameters, stack variables, etc. etc.

Using it as a convenient method to pass a type argument at runtime smells to me. There are times when typeof(T) necessary, but I found that they are rare and usually only needed when doing complex things with generics, unlike simple types of security. If I see this, I will definitely stop and ask myself why he is there.

+1
Oct. 16 '13 at 17:21
source share

Methods that relate to types usually do just that: Working with types.

IMO, Class.Method<SomeType>(); much better than Class.Method(typeof(SomeType));

But this is a matter of opinion, I think.

Consider LINQ .OfType<T>() , for example:

 personlist.OfType<Employee>().Where(x => x.EmployeeStatus == "Active"); 

against

 personlist.OfType(typeof(Employee)).Where(x => ((Employee)x).EmployeeStatus == "Active"); 

which would you prefer?

0
Aug 15 '13 at 16:26
source share

As already mentioned, this looks like a personal preference. In my experience, most methods that take an argument of type Type can be syntactically “sweetened” using the accompanying extension method.

So, in the case of your example, I would do extension as the second method. Using this approach, you get a solution for your second problem - no unnecessary unit tests are required. The first, however, remains; but then adding arguments will require refactoring in any case, so it will make it possible to change consumers of the extension method so that they use a modified version of the original.

Of course, this is just a personal opinion.

0
Oct. 16 '13 at 13:52
source share

A generic method takes precedence over a method with a parameter of type Type , because it can reference other common things using the provided type. This is especially useful in the following scenario:

 public string GetTypeName<T>() { return Cache<T>.TypeName; } private static class Cache<T> { public static readonly TypeName = GetTypeName(typeof(T)); } 

This cache is simple, there is no need to bother with dictionaries, and it is automatically thread safe.

Saying this, if the implementation does not use this opportunity, then the difference between them is just cosmetic.

0
Oct. 16 '13 at 14:10
source share



All Articles