I thought I'd post my answer, even though this question is old, because in my opinion, the accepted answer is wrong. That answer was pretty creative, so I don't mean to knock it. And for all I know, it could be what the OP really wanted.
But, as you'll see from my examples below, I think that in almost all cases, the idea of using the generic function described in the accepted answer is either (A) unnecessary or (B) flat-out wrong.
I've copied the generic function I'm 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 see some ways this function might be used:
Examples where the Generic Function is Unnecessary:
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--that is, it does return the correct values which are "string", "char", and "mycustomstruct", respectively. However in all cases like these, (i.e. where the generic function actually does return the correct type), the compiler knows ahead of time what the defined type of the variable is, and so does the programmer, of course (unless they got confused about their variable names). So the function is completely unnecessary, and the programmer may as well have done this:
var s = "hello";
var t = "string";
//or
foreach(char c in "banana")
WriteLine("char");
//or
foreach(MyCustomStruct x in listOfMyCustomStruct)
WriteLine("mycustomstruct");
That might seem naive at first, but think about it for a while...it might take a while for it to really sink in...Try to come up with ANY scenario where using the generic function provides accurate information at Runtime that isn't already known (and hence could be auto-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 just to demonstrate a minor annoyance with the generic function--that it is unnecessary in every case where it returns the correct result. But more importantly, take a look at the examples below. They demonstrates that in any other case, the result of the generic function is actually wrong if you expect the function to return the name of the true runtime type of the object. The function is actually only guaranteed to return the name of a type that the true value is assignable to, which might be an ancestor class, an interface, or "object" itself.
Examples where the Generic Function is Wrong
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 quite wrong as you can see. Now, I admit that the last two lines were a bit contrived to demonstrate the point (not to mention that TypeNameLower(j)
would actually be compiled to use the non-generic version of the function that is also part of the accepted answer--but you get the idea...)
The problem is that the function actually ignores the type of the object being passed in, and only uses the (compile-time) information of the generic parameter type 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 non-null, and it defaults to the compile-time/defined type when the type is null
.
Importantly, this function could be used WITHOUT a non-generic version!!
The result would be that the function would never return null
. The most general return value would be "object" e.g:
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 more consistent with the defined objective of the function, as requested by the OP. That is, if the OP really does want to find out what the type-name of the object was if it weren't null, then returning null would NEVER be an appropriate answer, because null ISN'T the name of any Type, and typeof(null) isn't defined.
Every variable in C# descends from System.Object
, so by definition, if the value weren't null
then it would be an Object
and that is in many cases the most that can be determined about a null reference at runtime.