tags:

views:

1076

answers:

12

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.

edit: Please see my additional comments posted further down...

A: 

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.

Mark Cidade
my unit tests for it did compile, but i had the actual out variable set to an object not a string.
rally25rs
+2  A: 

The type of your destination variable is always System.Object. You could just return Convert.ChangeType(paramVal, System.Object).

dub
+3  A: 

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) { ... }

Jelon
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 :)
rally25rs
+15  A: 

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.

Marcus Griep
Good suggestion! Second argument should be typeof(T) and not typeof(T).GetType().
Hallgrim
unfortunately that code "out T dest" does not compile because it can't find type "T". I'll research this option a bit more...
rally25rs
@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.
Esteban Brenes
C# Generics: http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx
Esteban Brenes
After Marcus' edit to add "<T>" to the method signature, this solution does compile and work! Thanks!
rally25rs
A: 

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) { //... }
Ryan
+6  A: 

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);
    }
}
Damian Powell
A: 

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...

David B
A: 

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 repedative, expecialy 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?

rally25rs
If two "string" declarations offends you, use "var val =..." instead. (it doesn't offend me, so I don't do this.)
David B
A: 

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...

rally25rs
+1  A: 

@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");
James Curran
Marcus edited his answer after I read it. Originally he had "GetParameterValue(out T dest)", instead of "GetParameterValue<T>(...)". His edited answer is correct.
rally25rs
A: 

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?

JB King
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.
rally25rs
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?
JB King
A: 

//The working answer

//based on your discussion eheheheheeh

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

}

protected void Page_Load(object sender, EventArgs e) { HtmlTable obj=null ; s(out obj);
}

/////////////////////////////////////////////////////////// Oh Yeah !!!