.NET : How do you get the Type of a null object?
Asked Answered
E

12

43

I have a method with an out parameter that tries to do a type conversion. Basically:

public void GetParameterValue(out object destination)
{
    object paramVal = "I want to return this. could be any type, not just string.";

    destination = null; // default out param to null
    destination = Convert.ChangeType(paramVal, destination.GetType());
}

The problem is that usually someone would call this like:

string output;
GetParameterValue(output);

This will fail because of:

destination.GetType()

destination is null, so we can't call .GetType() on it. We also can not call:

typeof(destination)

because destination is a variable name not a type name.

So is there any way to get the type of an object that is set to null? I would think there would have to be a way to know what type a storage location is without it being assigned anything.


Just to give a bit more info, I am trying to make a utility method that will grab the output parameters of an Oracle stored procedure. The issue is that DbParameter.Value is of type object.

What would be ideal would be for the developers to do something like:

string val = GetParameterValue("parameterName");

The notable thing is that there is no casting of types. In practice, you don't know the lparam of the "equals", so I went with:

string val;
GetParameterValue("parameterName", out val);

And figured within the method, I would know the destination type of the output variable. I guess that was a bad assumption. As an alternative, I also wrote the method:

public T GetParameterValue<T>(string paramName)

So the developers can do:

string val = GetParameterValue<string>("parameterName");

I find the explicit "string" declaration to be repetitive, especially since in practice, the destination if probably an object property and the oracle data type could change (think ORM):

MyObj.SomeProp = GetParameterValue<MyObj.SomeProp.GetType()>("parameterName");

But again, if MyObj.SomeProp is null, that .GetType() call fails. The VM has to know the type of MyObj.SomeProp, even when its null, right? or else how would it catch cast exceptions?


To partially solve my own problem, I can do:

MyObj.SomeProp = GetParameterValue<typeof(MyObj).GetField("SomeProp").GetType()>("parameterName");

The whole idea was to not have to explicitly use the Type in more than one place, so that if the data type changes, it only has to be changed in the destination object (MyObj.SomeProp) and in the DB. There has to be a better way...

Eulogize answered 31/10, 2008 at 18:33 Comment(0)
P
40

So is there any way to get the type of an object that is set to null? I would think there would have to be a way to know what type a storage location is without it being assigned anything.

Not necessarily. The best that you can say is that it is an object. A null reference does not point to any storage location, so there is no metadata from which it can make that determination.

The best that you could do is change it to be more generic, as in:

public void GetParameterValue<T>(out T destination)
{
    object paramVal = "Blah";
    destination = default(T);
    destination = Convert.ChangeType(paramVal, typeof(T));
}

The type of T can be inferred, so you shouldn't need to give a type parameter to the method explicitly.

Purehearted answered 31/10, 2008 at 18:43 Comment(6)
Good suggestion! Second argument should be typeof(T) and not typeof(T).GetType().Hanhhank
unfortunately that code "out T dest" does not compile because it can't find type "T". I'll research this option a bit more...Eulogize
@rally25rs: the T is a generic Type, in this case what is being suggested is that you use generics to determine the type of the method.Tabling
After Marcus' edit to add "<T>" to the method signature, this solution does compile and work! Thanks!Eulogize
+1 - This saved me from ignorantly adding the type parameter to my method (which I did not want to do)!Slingshot
You should still consider adding an overload which takes a type as parameter. First, this allow the method to be called with the type is not known at compile-time and only through a Type object. Second, if the caller knows the type at compile-time but is already working with the object's type, the method can be called with the existing Type object instead of generating a new one. Third, if called with a Type object, it will reduce the number of methods generated for the various types used as T.Peeress
R
12

It's possible if you don't mind declaring your method as a generic. Try this.

class Program
{
    public static void GetParameterValue<T>(out T destination)
    {
        Console.WriteLine("typeof(T)=" + typeof(T).Name);
        destination = default(T);
    }
    static void Main(string[] args)
    {
        string s;
        GetParameterValue(out s);
        int i;
        GetParameterValue(out i);
    }
}
Rusticate answered 31/10, 2008 at 18:46 Comment(0)
E
9

The following extension method returns the type of its parameter as it was declared, regardless of its contents:

using System;

namespace MyNamespace
{
    public static class Extensions
    {
        /// <summary>
        /// Gets the declared type of the specified object.
        /// </summary>
        /// <typeparam name="T">The type of the object.</typeparam>
        /// <param name="obj">The object.</param>
        /// <returns>
        /// A <see cref="Type"/> object representing type 
        /// <typeparamref name="T"/>; i.e., the type of <paramref name="obj"/> 
        /// as it was declared. Note that the contents of 
        /// <paramref name="obj"/> are irrelevant; if <paramref name="obj"/> 
        /// contains an object whose class is derived from 
        /// <typeparamref name="T"/>, then <typeparamref name="T"/> is 
        /// returned, not the derived type.
        /// </returns>
        public static Type GetDeclaredType<T>(
            this T obj )
        {
            return typeof( T );
        }
    }
}

Since this is an extension method, its argument can be a null reference, and all of the following works OK:

string myString = "abc";
object myObj = myString;
Type myObjType = myObj.GetDeclaredType();

string myNullString = null;
object myNullObj = myNullString;
Type myNullObjType = myNullObj.GetDeclaredType();

Note that myObjType and myNullObjType will both be set to System.Object, not System.String.

If you actually want the type of obj's contents when it's not null, then change the return line to:

return (obj != null) ? obj.GetType() : typeof( T );
Emulation answered 3/8, 2012 at 21:54 Comment(1)
You will get a RuntimeBinderException if obj is declared as dynamic.Gasparo
Z
3

Currently, you have no way of knowing what gets passed into the method. You can convert it into a generic method like this:

public void GetParameterValue<T>(out T destination)
{
   ...
}
Zermatt answered 31/10, 2008 at 18:42 Comment(1)
I actually did this same method as a 2nd way of getting to the same data. It was working, so I didn't include it in my post :)Eulogize
S
2

The type of your destination variable is always System.Object. You could just return

Convert.ChangeType(paramVal, System.Object).
Siliceous answered 31/10, 2008 at 18:41 Comment(0)
R
1

@Rally25s:

string val;
GetParameterValue("parameterName", out val);

It's unclear from your message (in the answers) what the problem with that one was. If declared as:

void GetParameterValue<T>(string parameterName, out T val)  { }

Than the call, as you wrote it above, will work (you don't need to specify the type). I'm guess that didn't work for you because you can't use a property as an "out" parameter. The way around that is to use both methods:

T GetParameterValue<T>(string parameterName, T ununsed)  { }

This would be called like this:

MyObj.SomeProp = GetParameterValue("parameterName", MyObj.SomeProp);

which is rather kludgey, but not the worse method presented.


A different method, which I've used in C++, but haven't tried yet in C#, is to have GetParameterValue() some object of you own design, and then implement a number of implicit cast operators for it.

class ParameterHelper
{
   private object value;
   public ParameterHelper(object value)   { this.value = value;  }

   public static implicit operator int(ParameterHelper v)
     { return (int) v.value; }

}
ParameterHelper GetParameterValue( string parameterName);

MyObj.SomeProp = GetParameterValue("parameterName");
Riccardo answered 31/10, 2008 at 19:22 Comment(1)
Marcus edited his answer after I read it. Originally he had "GetParameterValue(out T dest)", instead of "GetParameterValue<T>(...)". His edited answer is correct.Eulogize
S
0

In your example it would be null of type System.Object.

Does your example even compile? I get a "cannot convert from 'out string' to 'out object'" error.

Scute answered 31/10, 2008 at 18:35 Comment(1)
my unit tests for it did compile, but i had the actual out variable set to an object not a string.Eulogize
Z
0

I don't think it is possible to get the type when the value is null. Also, since you are calling inside GetParameterValue, the best you could do (when the value is null) is to get the type of the "destination" parameter which is "object". You might consider passing the Type as a parameter to GetParameterValue where you have more information, such as:

public void GetParameterValue(Type sourceType, out object destination) { //... }
Zygapophysis answered 31/10, 2008 at 18:45 Comment(0)
L
0

If there is no instance, there is no instance type.

The best you can do is use the type of the reference, which means if you have an object reference (as in the method in the question), the reference type is object.


You probably shouldn't be trying to convert a null instance of one type into a null instance of another type...

Louisiana answered 31/10, 2008 at 18:51 Comment(0)
R
0

At a theoretical level isn't a null really the same as a void pointer in C, which is to say that it holds a memory address and that's it? If so then it is similar to the case of a division by zero in Mathematics where the result is undefined.

One could do the following for this line:

string val = GetParameterValue<string>("parameterName");

Just remove that first string and now there isn't the repetition:

var val = GetParameterValue<string>("parameterName");

Not necessarily what you are looking for, though there is the question of how does one interpret null?

Rebane answered 31/10, 2008 at 20:1 Comment(2)
The issue wasnt "what is they type of null", it was "what is the type of this storage location that happens to currently be set to null" So "DataTable dt = null", the VM still knows dt is of Type DataTable.Eulogize
In setting a variable to null, it isn't pointing at anything, is my point. If you have 3 classes where each is derived from another, e.g. A is derived from B and B is derived from C, and you had a variable of type B that is assigned null, couldn't you assign a variable of type A to that or not?Rebane
S
0
//**The working answer**

//**based on your discussion eheheheheeh**

public void s<T>(out T varName)
{
    if (typeof (T) == typeof(HtmlTable)) 
    { 
         //////////       
    }

}

protected void Page_Load(object sender, EventArgs e) 
{
    HtmlTable obj=null ;
    s(out obj);       
}
Songsongbird answered 27/7, 2009 at 8:48 Comment(0)
F
-1

http://msdn.microsoft.com/en-us/library/58918ffs.aspx

or

private Hashtable propertyTable = new Hashtable();

public void LoadPropertyTypes()
{
    Type t = this.GetType();

    System.Reflection.MemberInfo[] memberInfo = t.GetMembers();

    foreach (System.Reflection.MemberInfo mInfo in memberInfo)
    {
        string[] prop = mInfo.ToString().Split(Convert.ToChar(" "));
        propertyTable.Add(prop[1], prop[0]);
    }
}
public string GetMemberType(string propName)
{
    if (propertyTable.ContainsKey(propName))
    {
        return Convert.ToString(propertyTable[propName]);
    }
    else{
        return "N/A";
    }
}

in that way we can use switch to manage different property types.

Fled answered 1/3, 2012 at 9:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.