C#:你会在哪里进行字符串转换/翻译功能?

时间:2009-12-08 12:06:30

标签: c# wpf winforms string design-patterns

我有一些相当简单的(至少当你跳过错误检查,事件的东西,等等)参数类。它们是“组装”的,就像这样:

public interface IParameter
{
    Type ValueType { get; }
    object Value { get; set; }
}

public interface IParameter<TValue> : IParameter
{
    new TValue Value { get; set; }
}

public abstract class ParameterBase<TValue> : IParameter<TValue>
{
    public abstract TValue Value { get; set; }
    object IParameter.Value
    {
        get { return Value; }
        set
        {
            if (value is TValue) Value = (TValue)value;
            else throw new ArgumentException("Wrong type.");
        }
    }
    public Type ValueType { get { return typeof(TValue); } }
}

因此,例如,要创建基于整数的参数,您将创建以下类:

public class NumberParameter : ParameterBase<int>
{
    private int number;
    public override int Value { get { return number; } set {number = value; } }
}

我的问题是其中一些参数会在用户界面中显示文本。例如,值类型可以是整数列表,但用户应该能够在文本框中键入这些整数,例如用逗号分隔。

您会将这种翻译/转换功能放在哪里?你会如何实现它?是否有一种聪明的方法可以使代码整洁?

目前我已经为需要进行此转换的参数添加了public string ValueAsText属性,但我觉得它使参数类的功能变得混乱,它完全不应该关心它。我正在考虑某种中间类,类型转换器,格式化程序+解析器,或......某些东西......也许只是在这里说喋喋不休...我有参数和文本框。我可以创建一个格式化程序和一个解析器,用于将值转换为字符串和从字符串转换值。但是如何以良好的方式连接点呢?

任何人都明白我的意思?任何聪明的想法?


澄清:我不想将参数本身转换为字符串,只将其值显示为字符串并从字符串中设置值。换句话说,参数实例本身必须保持不变。


更多说明:在ui中,参数由一个组件表示,该组件通常由带有参数名称的标签,文本框和/或其他输入控件组成。例如,日期参数将具有一个文本框(您可以在其中键入日期范围)和一个用于打开日期选择器的按钮(您可以在其中选择日期范围)。在这种情况下,参数TValue例如是IEnumerable<DateTime>,这是该参数应该真正需要的。但是因为我还希望用户能够在文本框中以字符串形式键入该日期范围,我需要将该字符串转换为某个日期的序列。目前我已经通过向date参数添加ValueAsText属性来做到这一点,该参数来回进行翻译。然后TextBox与ValueAsText属性“对话”,日期选择器与“Value”属性“对话”。这有效,但我觉得参数类做得太多了。我认为翻译工作属于介于两者之间的某个地方。但不确定连接的位置和方式是如何工作的。例如,我可以有一个范围解析器类,它可以将字符串解析为一系列日期和一个范围格式化程序类,它可以获取范围并从中创建一个字符串。但谁会创造它们,他们会住在哪里?我想第一步可能只是创建这些类并让它们存在于ValueAsText属性之后。这样,大多数功能至少被分离出来。但是,我真的不知道。我正在寻找想法,想要学习。这就是这个问题的原因:)

3 个答案:

答案 0 :(得分:2)

您是否考虑过为System.ComponentModel.TypeConverter类型类实现NumberParameter实现,使它们成为.NET世界中的一流公民,就像内置类型一样?这样你不仅可以处理来自string的转换(包括例如PropertyGrid控件中的支持,用于编辑'NumberParameter'而无需额外的工作,我认为这些值的数据绑定到{{1等等)但也可能是其他类型的转换/演员?

答案 1 :(得分:2)

这取决于你的要求;在一般中,我会在这里使用TypeConverter - 支持且可扩展:

TypeConverter converter = TypeDescriptor.GetConverter(typeof(TValue));
string text = converter.ConvertToString(value);
value = (TValue)converter.ConvertFromString(text);

这会处理文化等(请参阅重载 - 使用不变量进行序列化),如果控件外的类型没有转换器,您仍然可以添加一个:

TypeDescriptor.AddAttributes(typeof(Person),
    new TypeConverterAttribute(typeof(PersonConverter)));

您也可以简单地装饰自己的类型:

[TypeConverter(typeof(PersonConverter))]
public class Person {...}
但是,有一点需要注意;它(TypeDescriptor / System.ComponentModel)不在所有框架上;如果您需要支持CF / Silverlight / etc,您应该先检查它是否受支持。但是在常规.NET上很好。我有一些需要在所有框架上运行的序列化代码,而我无法使用它 - 我使用ToString()static T Parse(string)代替。

答案 2 :(得分:1)

我认为最干净(和标准)的方法是覆盖包含to string转换值的类的ToString方法,并提供Parse和{{1相反的方法。