我有一个商业类,其中包含各种股票交易价格类型的许多属性。这是该课程的一个示例:
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提供价格来识别价格类型。
E.g。
Today = "0D"
OneDay = "1D"
SixDay = "6D"
//..., etc.
首先,我将所有值加载到IDictionary()集合中,因此我们有:
[KEY] VALUE [0D] => 1.23456
[1D] => 1.23456
[6D] => 1.23456
....等等。
其次,我使用一个方法设置Price类的属性,该方法将上述集合作为参数,如下所示:
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
}
是否有更优雅的技术来设置大量属性? 谢谢, Ĵ
答案 0 :(得分:2)
使用委托映射/扩展方法,而不是使用字符串到十进制的映射并重复检查字典:
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;
}
}
然后你可以写prices.SetPrice("0D", 1.23456)
。
如果您愿意,可以在throw
方法的末尾添加SetPrice
语句,以处理id
与任何内容不匹配的情况。
答案 1 :(得分:0)
我会将字符串变量放入常量中,而不是每次运行方法时都声明它们:
private const string ONE_DAY = "D1";
如果您希望collection参数包含所有或大部分可能的值,那么您的代码可能很酷。如果您希望字典具有可能值的一小部分,则使用foreach循环和switch语句来设置值可能更有效,而不是每次都查找每个可能的值。它只取决于您需要处理多少值以及每次方法调用中获得的值。
答案 2 :(得分:0)
我看到它的方式,你有几个选择,取决于你的技能,你被允许改变当前POCO或其他类的方式:
LegacyKeyAttribute
,使用此属性扩充您的POCO gettors / settors。现在它变得微不足道了:遍历POCO的属性以找到当前遗留密钥的正确属性。最后一个选项需要对C#的理解比许多普通程序员更了解:编写和使用属性和反射。然而,最终它是最干净,最简单的解决方案(我将尝试提出一个例子)。
更新:这是一个小例子。同时,已经发布了许多改进建议,但没有一个仍使用属性,而您的情况似乎是理想的。为什么?我认为,它对现有代码造成的负担最小,这使得阅读和理解代码变得更加容易。
用法:
// 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]);
}
}
实施:
// the simplest attribute class is enough for you:
[AttributeUsage(AttributeTargets.Property)]
public class LegacyNameAttribute : Attribute
{
public string Name { get; set; }
public LegacyNameAttribute(string name)
{
this.Name = name;
}
}
// your Prices POCO class becomes easier to read
public class Prices
{
[LegacyName("0D")] public decimal Today { get; set; }
[LegacyName("1D")] public decimal OneDay { get; set; }
[LegacyName("6D")] public decimal SixDay { get; set; }
[LegacyName("10D")] public decimal TenDay { get; set; }
[LegacyName("12D")] public decimal TwelveDay { get; set; }
[LegacyName("1DA")] public decimal OneDayAdjusted { get; set; }
[LegacyName("6DA")] public decimal SixDayAdjusted { get; set; }
[LegacyName("10DA")] public decimal TenDayAdjusted { get; set; }
[LegacyName("100DA")] public decimal OneHundredDayAdjusted { get; set; }
}
// an extension method to ease the implementation:
public static class PricesExtensions
{
public static void SetPriceByLegacyName(this Prices price, string name, decimal value)
{
if (price == null)
throw new ArgumentException("Price cannot be null");
foreach (PropertyInfo prop in price.GetType().GetProperties())
{
LegacyNameAttribute legNameAttribute = (LegacyNameAttribute)
Attribute.GetCustomAttribute(prop, typeof(LegacyNameAttribute));
// set the property if the attribute matches
if (legNameAttribute != null && legNameAttribute.Name == name)
{
prop.SetValue(price, value, null);
break; // nothing more to do
}
}
}
}
这就是它的全部。即使添加了所有行,也可能是您的总行数减少了。但更重要的是,维护和使用变得更加容易。
答案 3 :(得分:0)
只是一个想法:
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_As_String,如:
IPrices_As_String obj = new Prices();
// set values from the legacy system
IPrices obj2 = obj as IPrices; // will give me the correct object..
HTH。
答案 4 :(得分:0)
在构造函数中定义属性字典,例如
private Dictionary<int, PropertyInfo> propertyDictionary = new ...
MyClass()
{
this.propertyDictionary.Add(0, this.GetType().GetProperty("FirstProperty");
...
}
然后使用索引属性进行访问
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
}
}
稍后您可以通过使用反射自动解析构造函数中的属性来改进此代码, 使用一个属性来添加所有属性,该属性可以告诉您id是什么。 (而不是在构造函数中手动添加它们。)