C#使用索引设置属性
我有一个业务类,它包含各种证券交易所价格类型的许多属性。这是该类的一个示例:C#使用索引设置属性,c#,coding-style,properties,C#,Coding Style,Properties,我有一个业务类,它包含各种证券交易所价格类型的许多属性。这是该类的一个示例: public class Prices { public decimal Today {get; set;} public decimal OneDay {get; set;} public decimal SixDay {get; set;} public decimal TenDay {get; set;} public decimal TwelveDay {get; set
public class Prices
{
public decimal Today {get; set;}
public decimal OneDay {get; set;}
public decimal SixDay {get; set;}
public decimal TenDay {get; set;}
public decimal TwelveDay {get; set;}
public decimal OneDayAdjusted {get; set;}
public decimal SixDayAdjusted {get; set;}
public decimal TenDayAdjusted {get; set;}
public decimal OneHundredDayAdjusted {get; set;}
}
我有一个遗留系统,它使用字符串ID来标识价格类型来提供价格
例如
Today = "0D"
OneDay = "1D"
SixDay = "6D"
//..., etc.
首先,我将所有值加载到IDictionary()集合,因此我们有:
[键]值[0D]=>1.23456
[1D]=>1.23456
[6D]=>1.23456
等等 其次,我使用将上述集合作为参数的方法设置Prices类的属性,如下所示:
SetPricesValues(IDictionary<string, decimal> pricesDictionary)
{
// TODAY'S PRICE
string TODAY = "D0";
if (true == pricesDictionary.ContainsKey(TODAY))
{
this.Today = pricesDictionary[TODAY];
}
// OneDay PRICE
string ONE_DAY = "D1";
if (true == pricesDictionary.ContainsKey(ONE_DAY))
{
this.OneDay = pricesDictionary[ONE_DAY];
}
//..., ..., etc., for each other property
}
setpricesvalue(IDictionary pricesDictionary)
{
//今天的价格
string TODAY=“D0”;
if(true==pricesDictionary.ContainsKey(今天))
{
this.Today=价格指数[今天];
}
//单日价格
字符串1_DAY=“D1”;
if(true==pricesDictionary.ContainsKey(一天))
{
this.OneDay=价格折扣[一天];
}
//…,…,等等,为彼此的财产
}
有没有更优雅的方法来设置大量属性?
谢谢
j我会将字符串变量放入常量中,而不是每次运行该方法时都声明它们:
private const string ONE_DAY = "D1";
如果您希望collection参数包含所有或大部分可能的值,那么您的代码可能很酷。如果您希望字典将有一小部分可能的值,那么使用foreach循环和switch语句来设置值可能会更有效,而不是每次都查找每个可能的值。这取决于您需要处理多少值以及每次方法调用中得到多少值。在我看来,您有一些选择,具体取决于您的技能、允许您更改当前POCO或其他类的方式:
- 如果必须使用字典,请创建一个类似的字典,将“0D”等映射到某一天的名称。循环浏览字典并使用简单反射进行赋值
- 如果可以更改读取数据的方式,请使用OneDay等来读取字典,而不是仅适用于外部应用程序的“0D”
- 创建一个属性,
,用该属性扩充您的POCO gettor/setors。现在它变得很简单:通过循环POCO的属性来找到当前遗留密钥的正确属性LegacyKeyAttribute
更新:这里有一个小例子。同时,已经发布了许多改进建议,但没有一个仍然使用属性,而您的案例似乎很理想。为什么?我相信,它对现有代码造成的负担最小,并且使阅读和理解代码更加容易 用法:
// any price:
Prices prices = new Prices();
prices.SetPriceByLegacyName("0D", 1.2345M);
// or, your loop becomes a bit easier:
SetPricesValues(IDictionary<string, decimal> pricesDictionary)
{
foreach(string key in pricesDictionary.Keys)
{
// assuming "this" is of type Prices (you didn't specify)
this.SetPriceByLegacyName(key, pricesDictionary[key]);
}
}
就这些。即使添加了所有行,也可能是总行数变少了。但更重要的是,它变得更易于维护和使用。这只是一个想法:
interface IPrices_As_String{
string OD { get; set; }
// other properties here...
}
interface IPrices{
decimal Today{get; set;}
}
class Prices : IPrices, IPrices_As_String{
public decimal Today { get; set; }
public string IPrices_As_String.OD {
get { return this.Today.ToString(); }
set {
if(!String.IsNullOrEmpty(value)){
this.Today = decimal.Parse(value);
}
}
}
}
然后,当我从遗留系统设置值时,我将使用接口上的Prices类作为IPrices_作为_字符串,如下所示:
IPrices_As_String obj = new Prices();
// set values from the legacy system
IPrices obj2 = obj as IPrices; // will give me the correct object..
HTH.在构造函数中定义属性字典,例如
private Dictionary<int, PropertyInfo> propertyDictionary = new ...
MyClass()
{
this.propertyDictionary.Add(0, this.GetType().GetProperty("FirstProperty");
...
}
稍后,您可以通过使用反射自动解析构造函数中的属性来改进此代码,
添加具有告诉您id是什么的属性的所有属性。
(不要在构造函数中手动添加它们)。不要使用字符串到十进制的映射并反复检查字典,而是使用委托映射/扩展方法:
public static class PriceConverter
{
private static readonly Dictionary<string, Action<Prices, decimal>> setters =
CreateSetterDictionary();
public static void SetPrice(this Prices p, string id, decimal newPrice)
{
Action<Prices, decimal> setter;
if (setters.TryGetValue(id, out setter))
setter(p, newPrice);
}
private static Dictionary<string, Action<Prices, decimal>>
CreateSetterDictionary()
{
var dic = new Dictionary<string, Action<Prices, decimal>>();
dic.Add("0D", (p, d) => p.Today = d);
dic.Add("1D", (p, d) => p.OneDay = d);
// etc.
return dic;
}
}
公共静态类价格转换器
{
专用静态只读字典设置程序=
CreateSetterDictionary();
公共静态void SetPrice(此价格为p,字符串id,十进制newPrice)
{
行动设定者;
if(setters.TryGetValue(id,out setter))
setter(p,newPrice);
}
专用静态字典
CreateSetterDictionary()
{
var dic=新字典();
加上(“0D”,(p,d)=>p.今天=d);
加上(“1D”,(p,d)=>p.OneDay=d);
//等等。
返回dic;
}
}
然后您可以编写prices.SetPrice(“0D”,1.23456)
如果愿意,请在
SetPrice
方法的末尾添加throw
语句,以处理id
不匹配的情况。如果(true==something\u或其他),请不要编写。<代码>真==<代码>是完全多余的,伤害了人们的眼睛。有些人可能认为它更清晰。虽然我同意你的观点,但它不会伤害我的眼睛(我见过更糟糕的代码,它应该被称为“伤害”);-)@亚伯:按照你的逻辑,(真==(真==foo))不是更清楚吗?你也可以为了无限的清晰而无限地继续它!哈哈,我不认为我自己更清楚,但是有些人做了(为什么不<代码>!false = =包容键())/>代码>。同样,他们可能会使用==false
而不是代码>或其他
。但是代码中还有一些明显的地方需要注意,这就是为什么Guazz提出了这个问题,我想:)索引可以是int/String/WhateverI,我不认为这会让它变得更容易。您仍然需要至少与他当前的实现一样多的代码来设置值,除非您使用反射,在这种情况下,您可以只使用属性或映射数组在字符串键和字段之间进行映射。@Matti-可能我遗漏了什么,但我没有使用任何反射-我直接设置属性&在集合中,将字符串转换为所需的相关类型…stringod{get;set;}
:您编写了一个O
,而不是0
,但请再次查看原始代码段:这些前缀是数字。及
decimal this[int index]
{
get
{
PropertyInfo property;
if (this.propertyDictionary.TryGetValue(index, out property))
{
// Not sure I remember the arguments right here:
property.SetValue(this, new object[] { value });
}
set
{
// Similar code
}
}
public static class PriceConverter
{
private static readonly Dictionary<string, Action<Prices, decimal>> setters =
CreateSetterDictionary();
public static void SetPrice(this Prices p, string id, decimal newPrice)
{
Action<Prices, decimal> setter;
if (setters.TryGetValue(id, out setter))
setter(p, newPrice);
}
private static Dictionary<string, Action<Prices, decimal>>
CreateSetterDictionary()
{
var dic = new Dictionary<string, Action<Prices, decimal>>();
dic.Add("0D", (p, d) => p.Today = d);
dic.Add("1D", (p, d) => p.OneDay = d);
// etc.
return dic;
}
}