泛型的应用无处不在,下面是项目代码片断,比较典型的泛型与反射应用,提供了类型安全.场景是项目中有基于exchange访问,使用了Exchange Web Services Manage API,我们需要写一个辅助查询的Enum属性类,以Dictionary的方式,Enum类型对Key,string类型为Value.最后转换成Manage API中具体查询类.
public enum ContactQueryEnum { DisplayName, NickName, CompleteName
…
好的,下面是转换方法:
/// <summary> /// Gets the EWS's Entity property auto conver to dictionary. /// </summary> /// <typeparam name="T">first dictionary key</typeparam> /// <typeparam name="K">second dictionary key</typeparam> /// <typeparam name="V">first dictionary value</typeparam> /// <typeparam name="U">second dictionary value</typeparam> /// <param name="dictionary">The dictionary.</param> /// <returns>IDictionary<PropertyDefinitionBase, U></returns> /// <remark>Author : PetterLiu 2008-12-24 15:11 </remark> public static IDictionary<PropertyDefinitionBase, U> GetEWSProperty<T, K, V, U>(IDictionary<K, V> dictionary) { if (dictionary != null) { IDictionary<PropertyDefinitionBase, U> queryparams = new Dictionary<PropertyDefinitionBase, U>(); FieldInfo[] fieldInfosItem = typeof(ItemSchema).GetFields(BindingFlags.Public | BindingFlags.Static); FillParamsDictionary<K, V, U>(fieldInfosItem, dictionary, queryparams); if (typeof(T) != typeof(ItemSchema)) { FieldInfo[] fieldInfosT = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Static); FillParamsDictionary<K, V, U>(fieldInfosT, dictionary, queryparams); } return queryparams; } return null; } #region FillParamsDictionary /// <summary> /// Fills the params dictionary. /// </summary> /// <typeparam name="K">second dictionary key</typeparam> /// <typeparam name="V">first dictionary value</typeparam> /// <typeparam name="U">second dictionary value</typeparam> /// <param name="fieldInfos1">The field infos1.</param> /// <param name="dictionary">The dictionary.</param> /// <param name="queryparams">The queryparams.</param> /// <remark>Author : PetterLiu 2008-12-24 15:11 </remark> private static void FillParamsDictionary<K, V, U>(FieldInfo[] fieldInfos1, IDictionary<K, V> dictionary, IDictionary<PropertyDefinitionBase, U> queryparams) { foreach (var info in fieldInfos1) { foreach (var pair in dictionary) { if (pair.Key.ToString() == info.Name) { PropertyDefinitionBase propertyDefinitionBase = info.GetValue(info) as PropertyDefinitionBase; queryparams.Add(propertyDefinitionBase, (U)(object)pair.Value); } } } } #endregion
PropertyDefinitionBase,ItemSchema是Exchange Web Services Manage API中的类,UnitTest:
/// <summary> /// Entities the convert reflection test. /// </summary> /// <remarks>author:Petter Liu http://wintersun.cnblogs.com </remarks> [Test] public void EntityConvertReflectionTest() { var searchparams = DictionaryHelper.CreateEnumKeyDictionaryInstance<ContactQueryEnum, string>(); searchparams.Add(ContactQueryEnum.BusinessAddressCity, "ShangHai"); searchparams.Add(ContactQueryEnum.CompanyName, "ABC"); IDictionary<PropertyDefinitionBase, string> searchpropertydic = ConvertUtlity.GetEWSProperty<ContactSchema, ContactQueryEnum, string, string>(searchparams); foreach (var filter in searchpropertydic) { //if search value was not null and empty,then add search parameter if (!string.IsNullOrEmpty(filter.Value)) { Trace.Write(string.Format("Key:{0}", filter.Key)); Trace.WriteLine(string.Format(" Value:{0}", filter.Value)); Assert.IsInstanceOf<PropertyDefinitionBase>(filter.Key); Assert.IsInstanceOf<string>(filter.Value); } } Assert.AreEqual(2, searchpropertydic.Count); }
另一个值得关注的细节,当我们使用Enum类型作为key值时,Dictionary的内部操作就需要将Enum类型转换为System.Object,这就导致了性能问题。
注意上面代码还有一个方法DictionaryHelper.CreateEnumKeyDictionaryInstance,这是专门为Enmu做key时Dictionary性能优化类.
public class DictionaryHelper { /// <summary> /// Creates the enum key dictionary instance. /// </summary> /// <typeparam name="K">K</typeparam> /// <typeparam name="V">V</typeparam> /// <returns>IDictionary with key and value</returns> /// <remarks>author PetterLiu http://wintersun.cnblogs.com </remarks> public static IDictionary<K, V> CreateEnumKeyDictionaryInstance<K, V>() where K : struct { return new Dictionary<K, V>(new EnumComparer<K>()); } }
关于EnumComparer可参考在Dictionary中使用枚举,以及Accelerating Enum-Based Dictionaries with Generic EnumComparer.
下面还是放上这个关键代码,利用C# 3.0中Lambda表达式:
/// <summary> /// EnumComparer /// </summary> /// <typeparam name="T">struct</typeparam> /// <example> /// <code> /// <![CDATA[ /// public enum DayOfWeek{//...} /// var dictionary = new Dictionary<DayOfWeek, int>(new EnumComparer<DayOfWeek>()); /// ]]> /// </code> /// </example> public class EnumComparer<T> : IEqualityComparer<T> where T : struct { /// <summary> /// Equalses the specified first. /// </summary> /// <param name="first">The first.</param> /// <param name="second">The second.</param> /// <returns>bool</returns> public bool Equals(T first, T second) { var firstParam = Expression.Parameter(typeof(T), "first"); var secondParam = Expression.Parameter(typeof(T), "second"); var equalExpression = Expression.Equal(firstParam, secondParam); return Expression.Lambda<Func<T, T, bool>> (equalExpression, new[] { firstParam, secondParam }). Compile().Invoke(first, second); } /// <summary> /// Gets the hash code. /// </summary> /// <param name="instance">The instance.</param> /// <returns>int</returns> public int GetHashCode(T instance) { var parameter = Expression.Parameter(typeof(T), "instance"); var convertExpression = Expression.Convert(parameter, typeof(int)); return Expression.Lambda<Func<T, int>> (convertExpression, new[] { parameter }). Compile().Invoke(instance); } }
小结:后期试着用AutoMapper来实现转换,发现对于这个多个类型关联转换,以及原生类设计特别性,没有能够成功.代码中随时存在这些小细节,
对于这些细节我们不能忽视.
Author: Petter Liu http://wintersun.cnblogs.com