我正在构建本地化目录并遇到设计困境。现在,目录存储了一个 Dictionary<string, IString> 来存储翻译,其中 IString 可以有两种类型: SingularPlural 。这是 IString 的简化版本:

public interface IString
{
    void SetSingular(string singular);

    string GetSingular(params object[] args);

    void SetPlural(PluralCategory category, string plural);

    string GetPlural(PluralCategory category, params object[] args);
}

然后,当我实现 Singular 时,我为复数方法抛出一个 NotSupportedException,它被目录捕获,而 Plural 对单数方法也做同样的事情。
public class Singular : IString
{
    // ...

    public string GetPlural(PluralCategory category, params object[] args)
    {
        throw new NotSupportedException(string.Format(
            "Singular strings don't support GetPlural({0}, {1})",
            category, args));
    }

    public void SetPlural(PluralCategory category, string plural)
    {
        throw new NotSupportedException(string.Format(
            "Singular strings don't support SetPlural({0}, {1})",
            category, plural));
    }
}

这种设计来自于要求keys对于单数和复数都必须是唯一的,但是我觉得实现不相关的方法和抛出NotSupportedException的味道不太好。

第二种设计是存储一个 Dictionary<string, StringType> 用于 key 检查,其中 StringType 是一个枚举,然后根据 Dictionary<string, Singular> 的值使用两个额外的字典 Dictionary<string, Plural>StringType 。这使它有点复杂,但不会破坏界面概念。

所以你怎么看?我的第一个想法是对 NotSupportedException 的不当使用吗?我应该选择第二个设计还是别的什么?

编辑: 基于@dasblinkenlight 想法的更清晰的解决方案是统一接口(interface)方法以将 SingularPlural 合并为一个。单数只有一个 PluralCategory.None ,而复数永远不允许包含这个类别。这受到 setter 方法的限制,不在特定实现定义的接口(interface)之外(setter 方法不在下面显示)。
public interface IString
{
    string GetString(PluralCategory category, params object[] args);
    bool HasCategory(PluralCategory category);
}

public class Singular : IString
{
    private string Text;

    public string GetString(PluralCategory category, params object[] args)
    {
        if (category == PluralCategory.None)
        {
            if (Text == null || args == null || args.Length == 0)
            {
                return Text;
            }
            return string.Format(Text, args);
        }
        return null;
    }

    public bool HasCategory(PluralCategory category)
    {
        return category == PluralCategory.None;
    }
}

public class Plural : IString
{
    private Dictionary<PluralCategory, string> Texts = new Dictionary<PluralCategory, string>();

    public string GetString(PluralCategory category, params object[] args)
    {
        string text;
        if (Texts.TryGetValue(category, out text))
        {
            if (text == null || args == null || args.Length == 0)
            {
                return text;
            }
            return string.Format(text, args);
        }
        return null;
    }

    public bool HasCategory(PluralCategory category)
    {
        return Texts.ContainsKey(category);
    }
}

最佳答案

你是对的,在这种情况下抛出 NotSupportedException 不是一个好主意。通常,您实现一个接口(interface)是为了提供一组通用操作,这些操作“统一”了一组不同的类,为一组通用操作提供不同的实现。

但是,在您的情况下,不同的类无法“统一”:它们不仅保留自己的实现,还保留自己的接口(interface)。当您尝试统一使用它们时,代码会引发异常。与将它们保持为 object 相比,通用接口(interface)并没有给你那么多 - 用户必须在调用之前知道 IString 后面的类,否则他们可能会看到 NotSupportedException

有几种方法可以解决这个问题:一种方法是统一单数和复数方法,返回比简单 string 更复杂的答案:

public enum SingularOrPluralCategory {
    Singular,
    // The rest of the PluralCategory enum values
}
public class StringForm {
    public string Text {get; private set;}
    public SingularOrPluralCategory Category {get; private set;}
}
public interface IString {
    // You may want to omit the setter from the interface, adding it to the class instead
    void SetForm(SingularOrPluralCategory category, string plural);
    StringForm GetForm(SingularOrPluralCategory category, params object[] args);
}

现在,单数实现将返回 StringFormSingular 中的 Category 值,而复数实现将返回 StringForm 与几个复数类别之一。尝试在 IString 的单数子类上设置复数类别可能仍然是一个错误,但您可以通过将 setter 移到该类上来解决这个问题,从而无法在 IString 的单数子类上调用具有类别的 setter。

关于c# - 什么时候使用 NotSupportedException 不好?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18049187/

10-12 01:36