views:

179

answers:

5

What I'm doing is looking up a value for a particular field in the hashtable. The object can be a handful of primitive types who's value is destined to be put inside XML but it comes out of the hashtable as an object. So I have the problem of needing to decide what the type is, cast it up and then use that types ToString. It would be nice if I didn't need to cast it but then it will call the ToString on the object type and not the counterpart method on the actual type.

The following code is functionally correct, but I'm not comfortable with it. Perhaps following this comfort path will lead to me being a purist. Either way I would very much appreciate a nicer way to write this if such exists.

public string GetColumnValue(string columnName)
        {
            object value = item[columnName];

            if (value == null)
                return string.Empty;

            if (value.GetType() == typeof(string))
            {
                return (string)value;
            }
            else if (value.GetType() == typeof(double))
            {
                return ((double)value).ToString();
            }
            ...
        }
+8  A: 

If all you are doing is calling ToString, due to the polymorphic nature of C#, the ToString will call the correct implementation, even if all you have is a reference to Object.

E.g.:

var d=DateTime.Now;
object od=d;
Console.WriteLine(od.ToString());
Console.WriteLine(d.ToString());   //same as previous line
spender
This works for the basic types, but may not work well for custom types - depends on what can be returned in item[columnName]...
Reed Copsey
Reed, can you give an example?
spender
I honestly didn't think this would work. So for arguments sake, how can you explicitly call a ToString implementation on a particular type of an inheritance tree?
Dan Revell
@Dan : all Objects in C# have ToString() defined... it is in the definition of the language.
Hogan
@Hogan I understand this but a lot of the time ToString will just return a string of the objects type. What I'm wondering is how do you call a specific implementation of ToString. Say I want to call the ToString for type Shape on an instance of type Circle where Circle : Shape. Circle might override the ToString but I don't want to take chances and explicitly call the Circle ToString for some reason.
Dan Revell
I would do that like this ((Shape)aCircleVar).ToString(); (Was this really your original question?)
Hogan
@Dan Revell: You'll always get the ToString() implementation of the actual type (or the most concrete type that overrides it). This is standard OO programming. @spender: THe issue is that custom types, by default, will return the typename. Also, if certain types wanted custom formatting, you'd still have to handle them specifically.
Reed Copsey
@Reed : Clearly the best way to handle this in 3.5+ is with helper functions. Make a helper for each type you want to handle that does not have a ToString() you like.
Hogan
@Reed Copsey So ((Shape)aCircleVar).ToString() wouldn't work? Or rather it would just call it for type Circle. It makes sense now but I was (hence the original question) under the impression that you could call ToString explicitly for a type. But if you can't all the better. Don't know why I would want to anyway.
Dan Revell
@all I said "helper function" above I meant to say "extension method" -- see my answer's edit.
Hogan
@Hogan - Unless `Circle` decorates its `ToString()` method with `new` rather than `override`, then the expression type has no influence at all on which method gets called. Only the runtime type of the object matters. `((Shape)aCircleVar).ToString()` is exactly the same as `aCircleVar.ToString()`.
Jeffrey L Whitledge
Yep, you are right. This is the fundamental difference between override and new.
Hogan
+1  A: 

Depending on your list of acceptable types, you may want to consider using Convert.ToString and/or the IConvertable interface.

This will allow you to handle most of the primitive types in one shot.

You will still need to handle your null check, however.

Reed Copsey
A: 

Why can't you just use .ToString() on value since .ToString() is inherited from object? The .ToString() for the appropriate type further up the inheritance chain will be called.

Jeff Hornby
Still needs the null check, though.
Reed Copsey
+1  A: 

edit

Test codes are here if anyone is interested: http://gist.github.com/raw/305787/dc5349d9f6fa37ee5d621b43ec92dade60fe1c8d/ToStringTests.cs

Below you will find my original answer. Someone pointed out that you might have a type which does not have a ToString() you like (because it uses Object or something higher up in the chain). The best way to handle this in 3.0+ is with a extension method like this:

    public static class ToStringExpander
    {
       public static string MyToString (this Object x)
       {
          return x.ToString();
       }

       public static string MyToString (this mytype x)
       {
          return "This is the to string of mytype!";
       }
    }

Now mytype will work with the GetColumnValue below if you change ToString() to MyToString()

original post

This will do what you want.

   public string GetColumnValue(string columnName)
    {
        object value = item[columnName];

        if (value == null)
            return string.Empty;

        return object.ToString();
    }

or if you want to look old school:

   public string GetColumnValue(string columnName)
    {
        return (item[columnName] == null ? string.Empty : item[columnName].ToString());
    }

of course true old school would be to make a #define macro...

Hogan
The method name resolution rules require that an object's member methods are selected in preference to any extension methods that might be in scope. So I'm pretty sure that what you are suggesting here will not work.
Jeffrey L Whitledge
Yeah, I just tested it, the book I was reading implied it would act like I described, I changed the answer to a new solution.
Hogan
A: 

ToString() is a virtual method. This means that any calls to that method will, at runtime, select the correct implementation (the "most derived type"). Since all the primative types override ToString() to do the correct thing, there is no reason for any casting to any type of variable.

For a virtual method, the type of the variable does not matter in selecting the correct implementation. All that matters is runtime type of the object being referenced.

int x = 10;
object o = x;
x.ToString();
o.ToString();

Both calls to ToString() will execute the same code (minus the unboxing that occurs in the object version, since int is a value type).

Jeffrey L Whitledge