C# 用于实现的常量字符串的最佳实践
假设我有一个界面:C# 用于实现的常量字符串的最佳实践,c#,string,oop,design-patterns,interface,C#,String,Oop,Design Patterns,Interface,假设我有一个界面: public interface IFeature { Task execFeature(); } 和两个实现: public class FirstFeature : IFeature { private IWebApi webApi; public FirstFeature(IWebApi webApi) { this.webApi = webApi; } public async Task execFe
public interface IFeature
{
Task execFeature();
}
和两个实现:
public class FirstFeature : IFeature
{
private IWebApi webApi;
public FirstFeature(IWebApi webApi)
{
this.webApi = webApi;
}
public async Task execFeature()
{
string response = await webApi.getClassName();
IResult result;
if(response==null)
result = new TextResult("Error accessing api - check internet connection/api address");
else
result = new TextResult("Hello dear user – the selected class name is " + response);
result.display();
}
}
public class SecondFeature : IFeature
{
private IWebApi webApi;
public SecondFeature(IWebApi webApi)
{
this.webApi = webApi;
}
public async Task execFeature()
{
List<string> classNames = new List<string>();
var classNameTasks = Enumerable.Range(1, 3).Select(i => webApi.getClassName()).ToArray();
classNames.AddRange((await Task.WhenAll(classNameTasks)));
IResult result;
if (classNames[0] == null)
result = new TextResult("Error accessing api - check internet connection/api address");
else
result = new TextResult("Hello dear user – we’ve selected three new class names for you, and they are " + classNames[0] + ", " + classNames[1] + ", and " + classNames[2]);
result.display();
}
}
公共类第一个功能:IFeature
{
私有IWebApi;
public FirstFeature(IWebApi webApi)
{
this.webApi=webApi;
}
公共异步任务execFeature()
{
string response=wait webApi.getClassName();
i结果结果;
如果(响应==null)
结果=新文本结果(“访问api时出错-检查internet连接/api地址”);
其他的
结果=新文本结果(“您好,亲爱的用户–所选类名为“+响应”);
result.display();
}
}
公共类第二个功能:IFeature
{
私有IWebApi;
公共第二功能(IWebApi webApi)
{
this.webApi=webApi;
}
公共异步任务execFeature()
{
List classNames=新列表();
var classNameTasks=Enumerable.Range(1,3).Select(i=>webApi.getClassName()).ToArray();
AddRange((wait Task.WhenAll(classNameTasks));
i结果结果;
if(类名[0]==null)
结果=新文本结果(“访问api时出错-检查internet连接/api地址”);
其他的
result=newtextResult(“您好,亲爱的用户–我们为您选择了三个新类名,分别为“+classNames[0]+”、“+classNames[1]+”和“+classNames[2]);
result.display();
}
}
如您所见,在这两种实现中,我都要执行result=newtextResult(“访问api时出错-检查internet连接/api地址”)代码>行以报告错误
OOP/良好设计中的最佳实践是什么,在我的所有实现中都可以访问一个常量error\u string
现在的情况是,代码是重复的。我认为没有最佳实践。这只是偏好的问题
我在静态类中存储常量
public static class Constants
{
public static class Messages
{
public const string Error = "Error accessing api...";
public const string Hello = "Hello ...";
}
}
用法
仅供参考:一些开发人员更喜欢Enum。将其放在一个静态类中:
internal static class ErrorMessage
{
public const string NoAccess = "Error accessing api - check internet connection/api address";
}
您可以通过以下方式引用:
result = new TextResult(ErrorMessage.NoAccess);
或者,您可以使用资源文件。我通常建议使用资源文件(根据项目设置创建)。如果您想使此代码更易于测试,您可能需要提供某种包装。除了您的功能显示消息这一事实之外,我认为它不应该这样做,如果您将消息放入代码中,您显然存在本地化问题。无论您将它放在何处以及如何访问它,您都不希望重新编译以获得不同的语言。你甚至不想重新编译来修复一个愚蠢的拼写错误
在代码中,使用错误代码。例如,这可以是枚举。然后在前端应用程序中,提供一个翻译服务(.NET有一个非常好的功能,称为“资源”)
通过这种方式,你可以为不同的前端提供不同的资源(比如法语资源,或者为语言更简单的儿童提供资源,或者为能够处理实际事务的技术人员提供资源)
此外,您还可以拥有一个自动前端,它可以对代码做出反应,而不必解析错误消息,也不必在有人纠正拼写错误或找到更友好的术语时抛出错误。并非我不同意@Win的答案,我认为,为了避免重复,将逻辑上与IFeature相关的Error和Hello常量放在不相关的静态类中可能不是合适的方法。如果目标是避免重复,那么我希望通过以下方式实现:
public abstract class Feature:IFeature
{
public static readonly string Error = "Error accessing api...";
public static readonly string Hello = "Hello ...{0}";
protected IWebApi webApi;
protected Feature(IWebApi webApi)
{
this.webApi = webApi;
}
public async Task execFeature()
{
var o = _execFeature();
IResult result;
if(o==null)
result = new TextResult(Error);
else
result = new TextResult( string.Format(Hello, o);
result.display();
}
protected abstract object _execFeature();
}
所以现在我不仅实现了代码重复的最佳最小化,还将错误和Hello放在了逻辑上属于它们的地方。第一个和第二个要素类现在可以从要素类继承:
public class FirstFeature:Feature
{
public FirstFeature(IWebApi webApi):base(webApi){}
protected override object _execFeature ()
{
//your code for first Feature
//return response if no error else return null
}
}
public class SecondFeature:Feature
{
public SecondFeature(IWebApi webApi):base(webApi){}
protected override object _execFeature ()
{
//your code for second Feature
//return class name[0] if no error else return null
}
}
这就是我的设计。我通常会根据信息的预期受众进行区分。因此,我将它们分为两类
无论类别如何,我都避免多次编写相同的代码(例如消息字符串)
开发者信息
- 在单元测试中显示的消息、仅在调试过程中显示的消息或记录到超详细诊断文件中的消息
- 开发者信息不需要本地化,且应使用开发者的语言书写。
例如,如果开发公司位于莫斯科,那么就有很强的理由用俄语编写开发人员信息
在实践中,许多开发人员选择英语
- 实现选项有多种。我通常保持简单,在静态类中使用字段。请注意,对于将显示消息的每种类型,您都可以有一个消息类,或者您可以有一个中心消息类,将多个类分组。您可以有嵌套的消息组。您还可以添加其他类型的常量,以便在代码中使用。。。正如我提到的,选项和偏好比比皆是。
public static class FeatureMessages
{
#region Public Fields
public const string ApiAccessError =
@"Error accessing api - check internet connection/api address";
public const string SelectedClassFormatString =
@"Hello dear user – the selected class name is {0}";
#endregion
}
用户消息
- 向最终用户显示的消息。例如,安装会在用户GUI菜单中的用户警告消息框中提示
- 这些消息应本地化
- 实现很简单,至少需要一个默认语言资源文件。有很多资源可以告诉你如何做到这一点,你可以看到一个简单的解释
一个选项是资源文件。特别是当你需要处理本地化时。你是说我应该把它放在一个类中?或者在接口文件中?internal
用于限制同一程序集(项目)内的使用。因此,如果您将整个内容公开为库/dll,它将不会被访问
public static class FeatureMessages
{
#region Public Fields
public const string ApiAccessError =
@"Error accessing api - check internet connection/api address";
public const string SelectedClassFormatString =
@"Hello dear user – the selected class name is {0}";
#endregion
}