C# .NET4.0中的动态:我做得对吗?
昨天,我在.NET4.0中使用新的C# .NET4.0中的动态:我做得对吗?,c#,dynamic,.net-4.0,C#,Dynamic,.net 4.0,昨天,我在.NET4.0中使用新的dynamic类型编写了第一行代码。我发现这很有用的场景如下: 我有一个类,它包含几个值列表。这可以是列表、列表、列表或任何类型的列表。它们的使用方式是,我向一个或多个列表中添加一个值。然后我“同步”它们,这样它们都会以相同的长度结束(那些太短的会用默认值填充)。然后我继续添加更多的值,再次同步等等。目标是其中一个列表中任何索引处的项目与另一个列表中同一索引处的项目相关。(是的,如果将所有这些都封装到另一个类中,可能会更好地解决这个问题,但这不是本例的重点。)
dynamic
类型编写了第一行代码。我发现这很有用的场景如下:
我有一个类,它包含几个值列表。这可以是列表
、列表
、列表
或任何类型的列表。它们的使用方式是,我向一个或多个列表中添加一个值。然后我“同步”它们,这样它们都会以相同的长度结束(那些太短的会用默认值填充)。然后我继续添加更多的值,再次同步等等。目标是其中一个列表中任何索引处的项目与另一个列表中同一索引处的项目相关。(是的,如果将所有这些都封装到另一个类中,可能会更好地解决这个问题,但这不是本例的重点。)
我在几个类中都有这个构造,所以我想使列表的同步尽可能通用。但由于列表的内部类型可能会有所不同,这并不像我最初想象的那样直截了当。但是,请进入今天的英雄:动态:)
我编写了以下帮助器类,它可以获取列表(任何类型)的集合以及每个列表的默认值:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Foo.utils
{
public class ListCollectionHelper
{
/// <summary>
/// Takes a collection of lists and synchronizes them so that all of the lists are the same length (matching
/// the length of the longest list present in the parameter).
///
/// It is assumed that the dynamic type in the enumerable is of the type Tuple<ICollection<T>, T>, i.e. a
/// list of tuples where Item1 is the list itself, and Item2 is the default value (to fill the list with). In
/// each tuple, the type T must be the same for the list and the default value, but between the tuples the type
/// might vary.
/// </summary>
/// <param name="listCollection">A collection of tuples with a List<T> and a default value T</param>
/// <returns>The length of the lists after the sync (length of the longest list before the sync)</returns>
public static int SyncListLength(IEnumerable<dynamic> listCollection)
{
int maxNumberOfItems = LengthOfLongestList(listCollection);
PadListsWithDefaultValue(listCollection, maxNumberOfItems);
return maxNumberOfItems;
}
private static int LengthOfLongestList(IEnumerable<dynamic> listCollection)
{
return listCollection.Aggregate(0, (current, tuple) => Math.Max(current, tuple.Item1.Count));
}
private static void PadListsWithDefaultValue(IEnumerable<dynamic> listCollection, int maxNumberOfItems)
{
foreach (dynamic tuple in listCollection)
{
FillList(tuple.Item1, tuple.Item2, maxNumberOfItems);
}
}
private static void FillList<T>(ICollection<T> list, T fillValue, int maxNumberOfItems)
{
int itemsToAdd = maxNumberOfItems - list.Count;
for (int i = 0; i < itemsToAdd; i++)
{
list.Add(fillValue);
}
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
命名空间Foo.utils
{
公共类ListCollectionHelper
{
///
///获取列表集合并对其进行同步,以便所有列表的长度相同(匹配
///参数中存在的最长列表的长度)。
///
///假设枚举中的动态类型为TupleCollectionT>,T>,即a
///元组列表,其中Item1是列表本身,Item2是默认值(用于填充列表)。In
///对于每个元组,列表和默认值的类型T必须相同,但元组之间的类型T必须相同
///可能会有所不同。
///
///具有ListT>和默认值T的元组集合
///同步后列表的长度(同步前最长列表的长度)
公共静态int SyncListLength(IEnumerable listCollection)
{
int maxNumberOfItems=LengthOfLongestList(列表集合);
PadListsWithDefaultValue(listCollection,maxNumberOfItems);
返回maxNumberOfItems;
}
私有静态int LengthOfLongestList(IEnumerable listCollection)
{
返回listCollection.Aggregate(0,(当前,元组)=>Math.Max(当前,元组.Item1.Count));
}
私有静态无效PadListsWithDefaultValue(IEnumerable listCollection,int maxNumberOfItems)
{
foreach(listCollection中的动态元组)
{
FillList(tuple.Item1、tuple.Item2、maxNumberOfItems);
}
}
私有静态void FillList(ICollection list、T fillValue、int maxNumberOfItems)
{
int itemsToAdd=maxNumberOfItems-list.Count;
对于(int i=0;i
下面是一组简短的单元测试,我用来验证我最终是否达到了预期的行为:
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Foo.utils;
namespace Foo.UnitTests
{
[TestClass]
public class DynamicListSync
{
private readonly List<string> stringList = new List<string>();
private readonly List<bool> boolList = new List<bool>();
private readonly List<string> stringListWithCustomDefault = new List<string>();
private readonly List<int> intList = new List<int>();
private readonly List<dynamic> listCollection = new List<dynamic>();
private const string FOO = "bar";
[TestInitialize]
public void InitTest()
{
listCollection.Add(Tuple.Create(stringList, default(String)));
listCollection.Add(Tuple.Create(boolList, default(Boolean)));
listCollection.Add(Tuple.Create(stringListWithCustomDefault, FOO));
listCollection.Add(Tuple.Create(intList, default(int)));
}
[TestMethod]
public void SyncEmptyLists()
{
Assert.AreEqual(0, ListCollectionHelper.SyncListLength(listCollection));
}
[TestMethod]
public void SyncWithOneListHavingOneItem()
{
stringList.Add("one");
Assert.AreEqual(1, ListCollectionHelper.SyncListLength(listCollection));
Assert.AreEqual("one", stringList[0]);
Assert.AreEqual(default(Boolean), boolList[0]);
Assert.AreEqual(FOO, stringListWithCustomDefault[0]);
Assert.AreEqual(default(int), intList[0]);
}
[TestMethod]
public void SyncWithAllListsHavingSomeItems()
{
stringList.Add("one");
stringList.Add("two");
stringList.Add("three");
boolList.Add(false);
boolList.Add(true);
stringListWithCustomDefault.Add("one");
Assert.AreEqual(3, ListCollectionHelper.SyncListLength(listCollection));
Assert.AreEqual("one", stringList[0]);
Assert.AreEqual("two", stringList[1]);
Assert.AreEqual("three", stringList[2]);
Assert.AreEqual(false, boolList[0]);
Assert.AreEqual(true, boolList[1]);
Assert.AreEqual(default(Boolean), boolList[2]);
Assert.AreEqual("one", stringListWithCustomDefault[0]);
Assert.AreEqual(FOO, stringListWithCustomDefault[1]);
Assert.AreEqual(FOO, stringListWithCustomDefault[2]);
Assert.AreEqual(default(int), intList[0]);
Assert.AreEqual(default(int), intList[1]);
Assert.AreEqual(default(int), intList[2]);
}
}
}
使用系统;
使用System.Collections.Generic;
使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用Foo.utils;
名称空间Foo.UnitTests
{
[测试类]
公共类DynamicListSync
{
私有只读列表stringList=新列表();
私有只读列表boolList=new List();
私有只读列表stringListWithCustomDefault=新列表();
私有只读列表intList=新列表();
私有只读列表listCollection=新列表();
私有常量字符串FOO=“bar”;
[测试初始化]
公共void InitTest()
{
添加(Tuple.Create(stringList,默认值(String));
添加(Tuple.Create(boolList,默认值(布尔));
添加(Tuple.Create(stringListWithCustomDefault,FOO));
添加(Tuple.Create(intList,默认值(int));
}
[测试方法]
public void syncEmptyList()
{
AreEqual(0,ListCollectionHelper.SyncListLength(listCollection));
}
[测试方法]
public void syncwithOneListHavingOnItem()
{
字符串列表。添加(“一”);
AreEqual(1,ListCollectionHelper.SyncListLength(listCollection));
Assert.AreEqual(“一”,stringList[0]);
AreEqual(默认值(布尔值),boolList[0]);
AreEqual(FOO,stringListWithCustomDefault[0]);
AreEqual(默认值(int),intList[0]);
}
[测试方法]
public void与AllListItems()同步
{
字符串列表。添加(“一”);
添加(“两个”);
添加(“三”);
boolList.Add(false);
boolList.Add(true);
stringListWithCustomDefault.Add(“一”);
AreEqual(3,ListCollectionHelper.SyncListLength(listCollection));
Assert.AreEqual(“一”,stringList[0]);
Assert.AreEqual(“两个”,stringList[1]);
Assert.AreEqual(“三”,stringList[2]);
arenequal(false,boolList[0]);
arenequal(true,boolList[1]);
AreEqual(默认值(布尔值),boolList[2]);
AreEqual(“一”,stringListWithCustomDefault[0]);
AreEqual(FOO,stringListWithCustomDefault[1]);
AreEqual(FOO,stringListWithCustomDefault[2]);
AreEqual(默认值(int),intList[0]);
AreEqual(默认值(int),intList[1]);
AreEqual(默认值(int),intList[2]);
}
}
}
所以,因为这是我第一次尝试动力学(无论是在C#还是在任何地方)
var listCollection = new List<IEnumerable<object>>();
listCollection.Add(new List<int>());