如何最好地处理应该在序列中运行的文本替换?

时间:2013-02-07 18:57:03

标签: .net sorting collections dictionary tuples

通常,当我们有一个模板文件和一些文本替换来运行时,我们创建一个Dictionary<string,string>,看起来像这样:

Dictionary<string,string> substitutions = new Dictionary<string, string>
{
    {"{firstname}", customer.FirstName },
    {"{lastname}", customer.LastName },
    {"{address}", "your address" },
    {"{siteurl}", _siteUrl },
};

if (customer.Address != null)
{
    substitutions["{address}"] = customer.GetAddress();
}

等等。然后我们可以做类似的事情:

email.Body = substitutions.Aggregate(template,
    (current, sub) => current.Replace(sub.Key, sub.Value));

获取替代模板。

我今天遇到过一种情况,我需要确保替换按特定顺序运行。

现在我可以确保它们以正确的顺序放入Dictionary并希望它们所列举的任意顺序保持这个序列 - 我从未见过Dictionary在其他一些序列中枚举,但不保证ICollection的顺序。

所以我觉得做这样的事情很有用(i++被用作“任何价值”的占位符:

SomeCollection<string,string,int> substitutions
    = new SomeCollection<string, string, int>
{
    {"{firstname}", customer.FirstName, i++ },
    {"{lastname}", customer.LastName, i++ },
    {"{address}", "your address", i++ },
    {"{siteurl}", _siteUrl, Int32.MaxValue }, // this should happen last
};

if (customer.Address != null)
{
    substitutions["{address}"] = customer.GetAddress();
}

我可以通过某种IComparerint值进行排序。

但后来我试图弄清楚如何制作这样一个集合,并且在写了一个由Dictionary<string, Tuple<int, string>>支持的东西后,我决定我的代码的优雅不值得它的压力。导致我(截止日期等)我可以将.Replace("{siteurl}", _siteUrl)添加到Aggregate电话的末尾,这样就可以充分发挥作用。

但令我烦恼的是,我已经放弃了本来可能是一件优雅的事情。我遇到的问题(除了试图纠缠Dictionary<string, Tuple<int, string>>作为ICollection<KeyValuePair<string,string>>的实现,并试图实现GetEnumerator方法,同时尽量不强调截止日期)我想要以下内容:

  • 使用上面的对象初始化语法声明它的能力。
  • 按键获取和设置成员的能力(因此以Dictionary<string, Tuple<int, string>>支持)。
  • foreach圈的功能可以按int的顺序排除。
  • 如果我不关心该项目的排序位置,则可以在不指定int的情况下添加(或初始化)项目。
  • 使用相对简洁的东西执行替换的能力,比如上面的Aggregate调用(可能传递IComparer我没有达到写作的目的)。

我遇到的问题是GetEnumerator实施,而我未能记住indexer overloading并不困难。

您将如何实施此类要求。我是在正确的轨道上还是忽略了更优雅的东西?我是否应该坚持使用Dictionary<string,string>并想出一些方法在开始或结束时插入新项目 - 或者如果我不关心该项目那么只是中间位置?

我还没有达到什么美丽,优雅的解决方案?你将如何满足这种需求?

2 个答案:

答案 0 :(得分:1)

好像你可以使用LINQ按替换顺序排序然后枚举。例如,如果你有Dictionary<string, Tuple<string, int>>,它将类似于:

Dictionary<string, Tuple<string, int>> subs = new Dictionary<string, Tuple<string, int>>
{
    {"{firstname}", Tuple.Create(customer.FirstName, i++) },
    {"{lastname}", Tuple.Create(customer.LastName, i++) },
};

// Now order by substitution order
var ordered =
   from kvp in subs
   orderby kvp.Value.Item2
   select kvp;
foreach (var kvp in ordered)
{
    // apply substitution
}

顺便说一下,Dictionary<TKey, TValue>并不保证枚举会按照添加顺序返回项目。我似乎记得在某些时候通过指望顺序而被烧毁,但它可能是其他一些集合类。在任何情况下,依靠无证件行为只是要求出错。

答案 1 :(得分:0)

Why are entries in addition order in a .Net Dictionary?

这个问题可能对你有所帮助 - 在当前版本的.NET中迭代字典的密钥将按顺序返回密钥,但由于合同无法保证这一点,因此在未来的.NET版本中可能会有所改变。如果这让您担心,请继续阅读。如果没有,只需迭代字典。

在我看来,最简单的解决方案是坚持使用Dictionary<string, string>方法并保持单独的List<string> substitutionOrder。迭代此列表,并使用这些值索引到您的字典中。

email.Body = substitutionOrder.Aggregate(template,
    (current, sub) => current.Replace(substitutions[sub].Key, substitutions[sub].Value));