我有以下结构,并且想要一个具有以下两个类的好处的解决方案。第一个类使用字符串和强类型成员:
public class UserSessionData
{
private string Get(string key)
{
throw new NotImplementedException("TODO: Get from external source");
}
private void Set(string key, string value)
{
throw new NotImplementedException("TODO: Set in external source");
}
public string CustomerNumber {
get { return Get("CustomerNumber"); }
set { Set("CustomerNumber", value); }
}
public string FirstName {
get { return Get("FirstName"); }
set { Set("FirstName", value); }
}
public string LastName {
get { return Get("LastName"); }
set { Set("LastName", value); }
}
// ... a couple of hundreds of these
}
我可以想象一种替代方案是Get
和Set
方法,其enum
参数。这是第二堂课:
public class UserSessionData
{
public enum What {
CustomerNumber, FirstName, LastName, // ...
}
public string Get (What what) { return MyExternalSource(what); }
public string Set (What what, string value) { return MyExternalSource(what); }
}
但是#2级的消费者方面并不漂亮:
UserSessionData.Get(UserSessionData.What.CustomerNumber)
将它与第一类比较:UserSessionData.CustomerNumber
在我的第一个类示例中是否有一种强类型的方法来调用Get和Set方法?换句话说:如何从两个类中获得好处,即强类型成员的可维护性和漂亮的语法?
答案 0 :(得分:34)
如果您使用.Net 4.5或更新版本,则可以使用CallerMemberNameAttribute,因此您可以这样调用它:
public string CustomerNumber {
get { return Get(); }
}
要使其工作,请通过将参数添加到参数来修改Get方法:
private string Get([CallerMemberName] string key)
{
...
}
性能提示:编译器会在调用站点插入一个字符串作为参数,因此速度很快。
如果您使用.Net 4.0或更早版本,您仍然可以使用强类型属性名称而不是手动键入字符串,但是您需要实现方法like this以从Expression中提取属性名称,然后你可以使用表达式调用它:
public string CustomerNumber {
get { return Get(() => this.CustomerNumber ); }
}
可以以相同的方式实现setter。
性能提示:字符串是在运行时提取的,因此比使用CallerMemberNameAttribute要慢。
答案 1 :(得分:8)
您可以使用T4模板生成课程。在T4模板中,您只需命名所有属性 - 您也可以通过枚举的反射来获取它们,但使用字符串数组更简单。
添加新项目 - >文字模板
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>
<# var properties = new string [] {
"CustomerNumber", // This is where you define the properties
"FirstName",
"LastName"
}; #>
class UserSessionData {
<#
foreach (string propertyName in properties)
{ #>
public string <#= propertyName #>{
get { return Get("<#= propertyName #>"); }
set { Set("<#= propertyName #>", value); }
}
<# } #>
}
更多信息@ Design-Time Code Generation by using T4 Text Templates
答案 2 :(得分:1)
带有一些扩展方法的枚举如何:
// usage:
[TestMethod]
public void example()
{
UserSessionData.CustomerNumber.Set("cust num");
Assert.AreEqual("cust num", UserSessionData.CustomerNumber.Get());
}
// implementation:
public enum UserSessionData
{
CustomerNumber,
FirstName,
}
public static class UserSessionDataHelper
{
private static Dictionary<string, string> values = new Dictionary<string, string>();
private static string GetName(this UserSessionData field)
{
return Enum.GetName(typeof(UserSessionData), field);
}
public static string Get(this UserSessionData field)
{
return values[field.GetName()];
}
public static void Set(this UserSessionData field, string value)
{
values[field.GetName()] = value;
}
}
答案 3 :(得分:0)
此模式允许松散耦合的资源键。出于可扩展性的目的,除了任何键类型之外的散列映射。您经常在IoC容器中看到系统消息。
根据我的经验,这种模式可以为所需文档的成本提供极大的灵活性。考虑使用约定而不是实现来解决问题。我尽可能坚持枚举值。
答案 4 :(得分:0)
如果您使用的是.NET 4.0或更高版本,则可以使用DynamicObject并覆盖其TryGetMember和TrySetMember方法,以完全动态完成此操作。 但这不会是强类型的。
答案 5 :(得分:0)
我不知道为什么还没有提出如此简单的灵魂:
public class UserSessionData
{
private string Get(What what)
{
throw new NotImplementedException("TODO: Get from external source");
}
private void Set(What what, string value)
{
throw new NotImplementedException("TODO: Set in external source");
}
public string CustomerNumber {
get { return Get(What.CustomerNumber); }
set { Set(What.CustomerNumber, value); }
}
// ...
}
public enum What
{
CustomerNumber, FirstName, LastName, // ...
}
您喜欢的用法:userSessionData.CustomerNumber
如果您的“外部来源”更喜欢字符串,则可以将What
枚举为私有并将枚举转换为字符串。