一个干净的方法将对象转换为其实际类型

5
我所做的是在哈希表中查找特定字段的值。该对象可以是少数几种基本类型之一,其值注定要放入XML中,但它作为一个对象从哈希表中出现。因此,我需要决定类型是什么,将其向上转换,然后使用该类型的ToString。如果不需要强制转换,则更好,但这将调用对象类型上的ToString而不是实际类型上的对应方法。
以下代码在功能上是正确的,但我对此感到不舒服。也许按照这条舒适路径会使我成为一个纯粹主义者。无论如何,如果存在更好的编写方式,我非常希望得到它。
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();
            }
            ...
        }
5个回答

8

如果你所做的只是调用ToString,由于C#的多态性质,ToString将会调用正确的实现,即使你只有一个Object的引用。

例如:

var d=DateTime.Now;
object od=d;
Console.WriteLine(od.ToString());
Console.WriteLine(d.ToString());   //same as previous line

1
这适用于基本类型,但对于自定义类型可能效果不佳 - 这取决于可以在 item[columnName] 中返回什么... - Reed Copsey
里德,你能举个例子吗? - spender
说实话,我并没有想到这会起作用。那么,为了论证,如何显式地调用继承树中特定类型的ToString实现呢? - Daniel Revell
1
@Reed:显然,在3.5+中处理这个问题的最佳方法是使用辅助函数。为您想要处理但没有您喜欢的ToString()的每种类型创建一个辅助函数。 - Hogan
1
@Hogan - 除非 Circle 使用 new 而不是 override 来修饰其 ToString() 方法,否则表达式类型对调用哪个方法没有任何影响。只有对象的运行时类型才有影响。((Shape)aCircleVar).ToString()aCircleVar.ToString() 是完全相同的。 - Jeffrey L Whitledge
显示剩余7条评论

1

编辑

如果有人感兴趣,测试代码在这里:http://gist.github.com/raw/305787/dc5349d9f6fa37ee5d621b43ec92dade60fe1c8d/ToStringTests.cs

下面是我的原始答案。有人指出你可能有一个没有你喜欢的ToString()的类型(因为它使用Object或者更高级的东西)。在3.0+中处理这个最好的方法是使用像这样的扩展方法:

    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!";
       }
    }

现在,如果你把 ToString() 改成 MyToString(),GetColumnValue 下面的代码就可以正常工作了。

原帖如下:

这个代码可以实现你想要的功能。

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

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

        return object.ToString();
    }

或者如果你想要看起来老派一些:

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

当然,真正的老派方法是使用 #define 宏定义...

1
方法名称解析规则要求优先选择对象的成员方法,而不是可能在作用域内的任何扩展方法。因此,我非常确定你在这里提出的建议不会起作用。 - Jeffrey L Whitledge
是的,我刚刚测试了一下,我正在阅读的书暗示它会像我描述的那样运作,我将答案更改为一个新的解决方案。 - Hogan

1
根据您可接受的类型列表,您可能需要考虑使用Convert.ToString和/或IConvertable interface。这将使您能够一次处理大多数基本类型。
但是,您仍然需要处理空值检查。

0

ToString() 是一个虚方法。这意味着在运行时,对该方法的任何调用都将选择正确的实现(即“最派生类型”)。由于所有基本类型都重写了 ToString() 来执行正确的操作,因此不需要将任何类型的变量强制转换。

对于虚方法,变量的类型在选择正确的实现时并不重要。唯一重要的是所引用对象的运行时类型。

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

对于这两个调用 ToString() 的方法,它们将执行相同的代码(除了在 object 版本中发生的拆箱操作,因为 int 是值类型)。


0
为什么不能在value上直接使用.ToString(),因为.ToString()是从object继承而来的呢?会调用继承链中更高层次的适当类型的.ToString()。

仍需要进行空值检查。 - Reed Copsey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接