首先关闭 - 是的,我看了一下这个问题:Is object creation in getters bad practice?。 我也不是在谈论在accessors / mutators中初始化一个对象,它是关于我希望以特定方式返回的对象的特定部分。
我的问题更具体;它不一定只适用于C#,但我目前正在寻找在我的C#项目中实现的解决方案。
我有一个带有字典的类,它将日期对象映射到十进制值。在一个访问器中,我想返回字典中所有键的列表,另一个访问器返回值。 我还想要的是一个访问器,它以特定的格式给出了十进制值。它看起来像这样:
class Class
{
// Some other properties...
// ....
private Dictionary<DateTime, decimal> dict;
public Class(Dictionary<DateTime, decimal> dict)
{
this.dict = dict;
}
private string FormatTheWayIWant(decimal dt)
{
// Format decimal value.
string s = String.Format("{0:F}", dt);
return s;
}
public ReadOnlyCollection<DateTime> DateTimes
{
get { return new ReadOnlyCollection<DateTime>(this.dict.Keys.ToList()); }
}
public ReadOnlyCollection<decimal> Values
{
get { return new ReadOnlyCollection<decimal>(this.dict.Values.ToList()); }
}
public ReadOnlyCollection<string> FormattedStrings
{
get
{
// Format each decimal value they way I want.
List<string> list = new List<string>();
foreach (decimal dt in dict.Keys)
{
list.Add(FormatTheWayIWant(dt));
}
return new ReadOnlyCollection<string>(list);
}
}
}
这样我可以进行以下调用(这是我的目标!):
DateTime dateTime = DateTimes[0];
decimal s = Values[0];
string formattedS = FormattedStrings[0];
这种方法的问题是每次调用FormattedStrings访问器时都会创建一个新列表,即使我只需要一个格式化的字符串。我知道这不是一个好的做法,可能会引入不必要的性能问题......
我想到的替代方案是:
decimal
类并实现自定义ToString()方法。 KeyValuePair<DateTime, decimal>
类并在我的班级中使用索引器。 我的问题是,有没有办法在分配值时使用访问器而不是方法,创建自定义类或对其他对象产生奇怪的副作用?
提前谢谢。
答案 0 :(得分:0)
这是VB,但你明白了......
Public Class Something
Public Property Items As Dictionary(Of DateTime, String)
Public Readonly Property FormattedItem(ByVal index As Int32) As String
' add error checking/handling as appropriate
Return Me.Items.Keys(index).ToString("custom format") ' or whatever your formatting function looks like.
End Property
End Class
答案 1 :(得分:0)
当然,这可以通过访问者来完成。您只需为已处理集合的每个所需元素创建3个单独的类。这些类应该有自己的索引器,因此您可以作为列表访问元素。不同之处在于,他们按需计算每个元素(称为lazy initialization)。所以它会像这样(你的FormattedStrings
的例子):
class Class
{
// ...
MyFormattedStrings FormattedStrings
{
get {return new MyFormattedStringsIndexer<string>(this.dict.Values.ToList());}
}
}
class MyFormattedStringsIndexer<T>
{
private IList<T> list; // we take only reference, so there is no overhead
public MyFormattedStringsCollection (IList<T> list)
{
this.list = list;
}
// the indexer:
public T this[int i]
{
get
{
// this is where the lazy stuff happens:
// compute the desired element end return it
}
set
{
// ...
}
}
}
现在您可以像这样使用Class
:
string formattedS = FormattedStrings[5];
您访问的每个元素将在您访问时计算。此解决方案还具有separating concerns的优势,因此,如果您必须为3个访问者之一实现不同的逻辑,那么只需扩展其中一个索引器即可。
您可以在此处详细了解indexeres:http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
答案 2 :(得分:0)
您的Dates
和Strings
属性获取者每次调用都会返回一个新列表。因此,如果呼叫者执行以下操作:
Class myClass = ...
for(i=0; i<myClass.Strings.Count; i++)
{
var s = myClass.Strings[i];
...
}
然后循环的每次迭代都会创建一个新列表。
我不清楚你在这里真正想要达到的目标。您正在Keys
中包含字典的Values
和ReadOnlyCollection
属性。这为您提供了一个索引器,由于未指定Dictionary<TKey, TValue>
中的键的顺序,因此它没有多大意义。
来到(最后!)你的问题,如果你想在&#34; lazy&#34;中进行格式化。方式,您可以创建一个实现只读IList<string>
的自定义类,并包装您的密钥列表(IList<DateTime>
)。大多数实现都是样板文件,您的索引器将执行格式化。您还可以缓存格式化的值,以便在多次访问时只格式化一次。类似的东西:
public class MyFormattingCollection : IList<string>
{
private IList<decimal> _values;
private IList<string> _formattedValues;
public MyFormattingCollection(IList<DateTime> values)
{
_values = values;
_formattedValues = new string[_values.Count];
}
public string this[int index]
{
get
{
var result = _formattedValues[index];
if (result == null)
{
result = FormatTheWayIWant(_values[index]);
_formattedValues[index] = result;
}
return result;
}
set
{
// Throw: it's a readonly collection
}
}
// Boilerplate implementation of readonly IList<string> ...
}
答案 3 :(得分:0)
它似乎是新课程的好候选人
public class MyObject
{
public DateTime Key {get;set;}
public String Name {get;set;}
public String FormattedString {get;}
}
然后它可以在任何容器中使用(List<MyObject>, Dictionary<MyObject>
等)。