【问题标题】:String.Format vs int.ToString in regards to iCustomFormatter issue关于 iCustomFormatter 问题的 String.Format 与 int.ToString
【发布时间】:2012-03-26 13:51:08
【问题描述】:

我有以下两行代码:

var BadResult = (100).ToString("B", new CustomFormatter ());
var GoodResult = String.Format("{0}", 100, new CustomFormatter ());

然而,BadResult 显然是坏的,而 GoodResult 是好的。我的 CustomFormatter 类是这样声明的:(还有一个我觉得相关的函数):

public class CustomFormatter 
               : IFormatProvider, ICustomFormatter
{
    public virtual Object GetFormat(Type formatType)
    {
        String formatTypeName = formatType.ToString();
        formatTypeName = formatTypeName;
        Object formatter = null;
        if (formatType == typeof(ICustomFormatter))
            formatter = this;
        return formatter;
    }
}

问题本身,当我以“良好的结果”运行代码行时,GetFormat 函数正在请求 CustomFormatter 的实例。

每当它用 Float.Tostring() 调用时,它都需要一个 NumberFormatInfo 的实例。

我最初跳到“我的 CustomFormatter 应该来自 NumberFormatInfo”。不幸的是,这个类是密封的。

所以:我需要做什么才能使用自定义格式化程序调用 Float.ToString()

谢谢!

【问题讨论】:

    标签: c# .net formatting string-formatting iformatprovider


    【解决方案1】:

    你的

     var GoodResult = String.Format("{0}", 100, new CustomFormatter ());
    

    没有使用 CustomFormatter。所以你的好结果似乎是通过默认值实现的。

    你想要的大概是:

     var GoodResult = String.Format(new CustomFormatter (), "{0}", 100);
    

    看看它是如何工作的。

    【讨论】:

    • 我需要 (100.0).ToString("{0}", new CustomFormatter());去工作。我的 String.Format 已经可以正常工作了。
    • 这是不可能的。需要 IFormatProvider 的唯一原因是允许传递 CultureInfo。无论如何,它在 CultureInfo 中使用 NumberFormatInfo 。所以 Int.ToString 唯一能真正接受的类型是 NumberFormatInfo。
    【解决方案2】:

    我不确定您是否可以将自定义格式化程序与 Number.ToString 一起使用。我在自定义格式化程序中看到的所有示例都使用 String.Format(例如this on the MSDN)。

    建议你试试扩展方法:

    public static class MyExt 
    {
        public static string ToFormattedString(this float This, string format, IFormatProvider provider)
        {
            return String.Format(provider,"{0}", new object[] {This});
        }
    }
    
    //now this works
    var NoLongerBadResult = (100F).ToFormattedString("B", new CustomFormatter ());
    

    编辑好的,我想我明白了。您需要更改当前的 NumberFormatInfo 并从 GetFormat 中返回:

    public class CustomFormatter :  IFormatProvider, ICustomFormatter
    {
        public object GetFormat(Type formatType)
        {
            if (formatType == typeof(ICustomFormatter))
                return this;
            else if(formatType == typeof(NumberFormatInfo))
            {
                NumberFormatInfo nfi = (NumberFormatInfo)NumberFormatInfo.CurrentInfo.Clone(); // create a copy of the current NumberFormatInfo
                nfi.CurrencySymbol = "Foo"; // change the currency symbol to "Foo" (for instance)
                return nfi; // and return our clone
            }
            else
                return null;
        }
    
        public string Format(string fmt, object arg, IFormatProvider formatProvider)
        {
            return "test";
        }
    }
    

    现在可以了:

    var NowItWorks = (100).ToString("C", new CustomFormatter ());
    var GoodResult = String.Format(new CustomFormatter (),"{0}", 100);
    Console.WriteLine(NowItWorks); // Foo 100.00
    Console.WriteLine(GoodResult); // test
    

    【讨论】:

    • 从我的互联网侦探工作看来,这似乎是解决方案。但是,为什么要允许您提供 icustomformatter 的 float.tostring() 重载?
    • @greggorob64 你说得对,它应该是可能的。 Single.ToString 的文档说“提供程序参数是一个 IFormatProvider 实现,其 GetFormat 方法返回一个 NumberFormatInfo 对象”,因此似乎应该有一种方法可以创建一个 NumberFormatInfo 对象并从您的自定义 getformat 中返回它。不过,我还没有找到办法……但我仍在尝试
    • @greggorob64 好的,所以...您的自定义提供程序可以工作,但是如果您将它与 Number.Tostring 一起使用,则您只能使用 NumberFormatProvider 理解的格式,因此 B 不起作用(但如果您尝试(100).ToString("C", new CustomFormatter ()); 它可以工作,并且 100 被格式化为货币)。您可能可以返回一个自定义 NumberFormatProvider,例如,您可以在其中更改小数点的符号,但您仅限于 NumberFormatInfo 本身允许您自定义的更改类型
    • 不幸的是,NumberFormatInfo 是密封的,所以我没有机会修改它。
    • 如果我错了,请纠正我,但这不允许使用完整的自定义格式字符串(例如,我想添加一个“B”格式的键字母。这个只允许我修改 NumberFormatInfo 可修改的项目
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 2022-07-07
    相关资源
    最近更新 更多