为什么对象没有接受 IFormatProvider 的重载?

发布于 2024-12-05 18:54:28 字数 1643 浏览 3 评论 0原文

例如,将十进制转换为字符串时,您可以使用CultureInfo.InvariantCulture并将其作为IFormatProvider传递。但为什么这个重载不在 object 中呢?

一个不错的实现是:

public virtual string ToString()
{
   // yadayada, usual ToString
}

public virtual string ToString(IFormatProvider provider)
{
   return ToString();
}

这不会对 object 类造成任何损害或好处,但从它派生的对象可以替代重载,并且当您不确定时调用它会容易得多类型。

让我遇到这个问题的是当我创建一个方法来获取类的所有属性并将其写入 xml 时。由于我不想检查对象的类型,因此我只是调用了 ToString。但如果这是一个十进制,输出将基于线程的 CurrentCulture,这不是最佳的。我能看到的唯一解决方法是将 CurrentCulture 更改为 InvariantCulture,然后将其改回之前的状态。但这会很难看,因为我必须编写 try finally 块等。

我当前的代码是:

        foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
            Where(c => ValidTypes.Contains(c.PropertyType)))
        {
            var value = property.GetValue(order, null);
            if (value != null)
            {
                writer.WriteElementString(property.Name, 
                value.ToString());
            }
        }

但我希望它是:

        foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
            Where(c => ValidTypes.Contains(c.PropertyType)))
        {
            var value = property.GetValue(order, null);
            if (value != null)
            {
                writer.WriteElementString(property.Name, 
                value.ToString(CultureInfo.InvariantCulture));
            }
        }

object 上不重载有什么好处?

When converting for instance a decimal to a string, you use the CultureInfo.InvariantCulture and pass it as an IFormatProvider. But why is this overload not in object?

A nice implementation would be:

public virtual string ToString()
{
   // yadayada, usual ToString
}

public virtual string ToString(IFormatProvider provider)
{
   return ToString();
}

This would cause no harm or benefit to the object class, but objects deriving from it can instead override the overload and it will be a lot easier to call it when you are unsure of the type.

The problem that made me run into this was when I was making a method that would be getting all properties of a class and writing it to xml. As I didn't want to check the type of the object, I just called ToString. But would this have been a decimal, the output would be based on the CurrentCulture of the thread, which is not optimal. The only workaround I can see is changing the CurrentCulture to InvariantCulture and then changing it back to whatever it was before. But that would just be ugly as I would have to write try finally blocks etc.

My current code is:

        foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
            Where(c => ValidTypes.Contains(c.PropertyType)))
        {
            var value = property.GetValue(order, null);
            if (value != null)
            {
                writer.WriteElementString(property.Name, 
                value.ToString());
            }
        }

But I would want it to be:

        foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
            Where(c => ValidTypes.Contains(c.PropertyType)))
        {
            var value = property.GetValue(order, null);
            if (value != null)
            {
                writer.WriteElementString(property.Name, 
                value.ToString(CultureInfo.InvariantCulture));
            }
        }

Any benefit of not having this overload on object?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不打扰别人 2024-12-12 18:54:28

尝试将您的 value 转换为 IFormattable

foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
       Where(c => ValidTypes.Contains(c.PropertyType)))
{
    var value = property.GetValue(order, null);
    if (value != null)
    {
        var formattable = value as IFormattable;
        writer.WriteElementString(property.Name, 
        formattable == null ? value.ToString() : formattable.ToString(null, CultureInfo.InvariantCulture));
    }
}

Try to cast your value to IFormattable:

foreach (var property in typeof(Order).GetProperties(BindingFlags.Public | BindingFlags.Instance).
       Where(c => ValidTypes.Contains(c.PropertyType)))
{
    var value = property.GetValue(order, null);
    if (value != null)
    {
        var formattable = value as IFormattable;
        writer.WriteElementString(property.Name, 
        formattable == null ? value.ToString() : formattable.ToString(null, CultureInfo.InvariantCulture));
    }
}
懵少女 2024-12-12 18:54:28

Peter 解决方案的便捷扩展方法(经过修改以测试 IConvertible)。

public static string ToInvariantString(this object obj)
{
    return obj is IConvertible ? ((IConvertible)obj).ToString(CultureInfo.InvariantCulture)
        : obj is IFormattable ? ((IFormattable)obj).ToString(null, CultureInfo.InvariantCulture)
        : obj.ToString();
}

Handy extension method of Peter's solution (modified to test also for IConvertible).

public static string ToInvariantString(this object obj)
{
    return obj is IConvertible ? ((IConvertible)obj).ToString(CultureInfo.InvariantCulture)
        : obj is IFormattable ? ((IFormattable)obj).ToString(null, CultureInfo.InvariantCulture)
        : obj.ToString();
}
长不大的小祸害 2024-12-12 18:54:28

请尝试以下方法之一:

string valueString = XmlConvert.ToString(value);
string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);

XmlConvert.ToString() 是为 XML 设计的,因此它会使事情更接近 XML 规范,例如使用“true”而不是“True”。然而,它也比 Convert.ToString() 更脆弱。例如,由于 UTC 时间,这将引发异常:

XmlConvert.ToString(DateTime.UtcNow)

但这有效:

XmlConvert.ToString(DateTime.UtcNow, "o")

Try one of these:

string valueString = XmlConvert.ToString(value);
string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);

XmlConvert.ToString() is made for XML, so it will keep things closer to the XML spec, such as using "true" instead of "True". However, it is also more brittle than Convert.ToString(). For example, this will throw an exception because of the UTC time:

XmlConvert.ToString(DateTime.UtcNow)

but this works:

XmlConvert.ToString(DateTime.UtcNow, "o")
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文