我正在构建本地化目录并遇到设计困境。现在,目录存储了一个 Dictionary<string, IString>
来存储翻译,其中 IString
可以有两种类型: Singular
或 Plural
。这是 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)方法以将
Singular
或 Plural
合并为一个。单数只有一个 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);
}
现在,单数实现将返回
StringForm
与 Singular
中的 Category
值,而复数实现将返回 StringForm
与几个复数类别之一。尝试在 IString
的单数子类上设置复数类别可能仍然是一个错误,但您可以通过将 setter 移到该类上来解决这个问题,从而无法在 IString
的单数子类上调用具有类别的 setter。关于c# - 什么时候使用 NotSupportedException 不好?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18049187/