Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the lowercase name of an object, even when null, in C# [duplicate]

Tags:

c#

Jeff is correct. That's like asking what kind of cake would have been in an empty box with no label.

As an alternative to Fortran's answer you could also do:

string TypeNameLower<T>(T obj) {
   return typeof(T).Name.ToLower(CultureInfo.InvariantCulture);
}

string TypeNameLower(object obj) {
   if (obj != null) { return obj.GetType().Name.ToLower(CultureInfo.InvariantCulture); }
   else { return null; }
}

string s = null;
TypeNameLower(s); // goes to the generic version

That way, C# will pick the generic one at compile time if it knows enough about the type you're passing in.


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.


// Uses the compiler's type inference mechanisms for generics to find out the type
// 'self' was declared with in the current scope.
static public Type GetDeclaredType<TSelf>(TSelf self)
{
    return typeof(TSelf);
}

void Main()
{
    // ...

    Foo bar;
    bar = null;

    Type myType = GetDeclaredType(bar);
    Console.Write(myType.Name);
}

Prints:

Foo

I posted this also at a similar topic, I hope it's of any use for you. ;-)


if (o == null) return "null";
else return o.GetType().Name.ToLower();

simple solution for a simple problem :-p


As others mention, you can't. This is actually a well-known issue with languages that allow pure null references to objects. One way to work around it is to use the "Null Object pattern". The basic idea is that instead of using null for empty references, you assign to it an instance of a "do nothing" object. For example:

public class Circle
{
    public virtual float Radius { get; set; }

    public Circle(float radius)
    {
        Radius = radius;
    }
}

public class NullCircle : Circle
{
    public override float Radius 
    { 
        get { return float.NaN; }
        set { }
    }

    public NullCircle() { }
}

You can then pass an instance of NullCircle instead of null and you will be able to test its type like in your code.


To the best of my knowledge you can't. Null indicates the absence of a value and is not distinct for different types.