2

通常,当我们有一个模板文件和一些要运行的文本替换时,我们创建一个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以正确的顺序放入,并希望它们枚举的任意顺序保持该顺序 - 我从未见过 aDictionary以其他顺序枚举,但 an 的顺序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();
}

我可以通过IComparer某种方式对int价值进行排序。

但后来我试图弄清楚如何制作这样一个集合,并且在尝试编写由 a 支持的东西失败之后Dictionary<string, Tuple<int, string>>,我决定我的代码的优雅不值得它给我带来的压力(考虑到最后期限等) on) 并且我可以在通话.Replace("{siteurl}", _siteUrl)结束时添加Aggregate

但让我烦恼的是,我已经放弃了本来可以很优雅的东西。我遇到的问题(除了试图让 aDictionary<string, Tuple<int, string>>成为一个实现ICollection<KeyValuePair<string,string>>并弄清楚如何实现这些GetEnumerator方法,同时尽量不强调截止日期)是我想要以下内容:

  • 使用上面的对象初始化器语法简单地声明它的能力。
  • 通过键获取和设置成员的能力(因此支持 a Dictionary<string, Tuple<int, string>>)。
  • 有一个foreach循环按顺序拉出东西的能力int
  • int如果我不关心该项目的排序位置,则无需指定添加(或初始化)项目的能力。
  • 使用相对简洁的方法执行替换的能力,例如Aggregate上面的调用(可能传入IComparer我没有写到的内容)。

我被困住的是GetEnumerator实现和我没有记住索引器重载并不困难。

你将如何实现这样的要求。我是在正确的轨道上还是我忽略了一些更优雅的东西?我应该坚持 aDictionary<string,string>并想出一些方法在开头或结尾插入新项目 - 或者如果我不关心那个项目,就在中间插入?

我只是没有得到什么漂亮、优雅的解决方案?您将如何满足这种需求?

4

2 回答 2

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>不保证枚举将按照添加的顺序返回项目。我似乎记得在某个时候指望订单而被烧毁,但它可能是其他一些集合类。在任何情况下,指望无证行为只是要求出错。

于 2013-02-07T19:35:52.377 回答
0

为什么 .Net 字典中的条目要另外排序?

这个问题可能会对您有所帮助 - 在当前版本的 .NET 中迭代字典的键将按顺序返回键,但由于合同不保证这一点,它可能会在未来的 .NET 版本中发生变化。如果这让您担心,请继续阅读。如果没有,只需遍历字典。

在我看来,最简单的解决方案是坚持你的Dictionary<string, string>方法并维护一个单独的List<string> substitutionOrder. 遍历此列表,并使用这些值索引到您的字典中。

email.Body = substitutionOrder.Aggregate(template,
    (current, sub) => current.Replace(substitutions[sub].Key, substitutions[sub].Value));
于 2013-02-07T19:12:53.807 回答