I thought that I would send my answer, although this question is old, because, in my opinion, the accepted answer is incorrect. This answer was pretty creative, so I'm not going to shoot it down. And for all that I know, it could be what the OP really wanted.
But, as you will see from my examples below, I think that in almost all cases the idea of using the common function described in the accepted answer is either (A) not needed or (B) wrong. I copied the generic function that I am talking about from the accepted answer and pasted it below for reference:
string TypeNameLower<T>(T obj) { return typeof(T).Name.ToLower(); }
Now let's look at some ways to use this function:
Examples when a common function is not needed:
var s = "hello"; var t = TypeNameLower(s); //or foreach(char c in "banana") WriteLine(TypeNameLower(c)); //or foreach(MyCustomStruct x in listOfMyCustomStruct) WriteLine(TypeNameLower(x));
In these examples, the function works, i.e. returns the correct values, which are "strings", "char" and "mycustomstruct" respectively. However, in all cases like these (i.e., when the general function really returns the correct type), the compiler knows in advance what a certain type of variable is, and, of course, the programmer (unless they are confused by their variable names). Thus, the function is completely unnecessary, and the programmer can do this too:
var s = "hello"; var t = "string"; //or foreach(char c in "banana") WriteLine("char"); //or foreach(MyCustomStruct x in listOfMyCustomStruct) WriteLine("mycustomstruct");
It may seem naive at first, but think about it for a while ... it may take some time for it to really drown ... Try to find ANY scenario in which using a common function provides accurate information on the Runtime that is not yet known (and therefore can be automatically generated by the compiler or code generation utilities such as T4 templates) at compile time .
Now, the point of the previous set of examples was to demonstrate a minor annoyance with a common function - that it is not needed in every case when it returns the correct result. But more importantly, take a look at the examples below. They show that in any other case, the result of the generic function is actually incorrect if you expect the function to return the name of the true type of the runtime of the object. The function actually only guaranteed to return a type name, which can be assigned a true value, which can be an ancestor class, interface or the object itself.
Examples where a common function does not match
Stream ms = new MemoryStream(); IEnumerable str = "Hello"; IComparable i = 23; object j = 1; TypeNameLower(ms); //returns "stream" instead of "memorystream" TypeNameLower(str); //returns "ienumerable" instead of "string" TypeNameLower(i); //returns "icomparable" instead of "int32" TypeNameLower(j); //returns "object" instead of "int32" TypeNameLower<object>(true); //returns "object" instead of "bool"
In all cases, the results are completely wrong, as you can see. Now I admit that the last two lines were a little far-fetched to demonstrate this point (not to mention that TypeNameLower(j) will actually be compiled to use a non-universal version of the function, which is also part of the accepted answer - but you get idea ...)
The problem is that the function actually ignores the type of the transmitted object and uses only information about the generalized parameter (compilation time) to return the value.
A better implementation would be as follows:
string TypeNameLower<T>(T obj) { Type t; if (obj == null) t = typeof(T); else t = obj.GetType(); return t.Name.ToLower(); }
Now the function returns the name of the true runtime type whenever the object is not null, and the default is to use the compile time / specific type when the type is null .
It is important to note that this function can be used WITHOUT a universal version! The result will be that the function will never return null . The most common return value will be "object", for example:
object x = null; string s = null; byte[] b = null; MyClass m = null; TypeNameLower(x); // returns "object" TypeNameLower(s); // returns "string" TypeNameLower(b); // returns "byte[]" TypeNameLower(m); // returns "myclass"
Note that this is actually a function more consistent with the intended purpose, as requested by the OP. That is, if the OP really wants to know what the object type name is, if it was not null, then returning null will never be a suitable answer, since null is NOT a name of any type and typeof (null) is not defined.
Each variable in C # is omitted from System.Object , so by definition, if the value was not null , then it would be Object , and in many cases this is the most that can be determined with respect to a null reference at runtime.