我正在创建一个框架,旨在允许 Web 开发人员创建 CRUD 页面,而无需通过重复步骤。
为此,我想提供“默认”方法来执行排序、过滤等操作。使用我的框架的开发人员可以选择提供自己的方法,但应该有一个在许多情况下都可以使用的默认方法。
与实体框架兼容对我来说尤其重要。
DynamicMethod
我已经使用允许通过搜索键对实体框架生成的任意类进行“通用”过滤的类成功实现了默认过滤功能。
我正在尝试对排序做类似的事情,但我遇到了问题。该OrderBy
方法有两个类型参数,第一个是实体类型,第二个是“键”类型。键入的这个键需要与用户想要排序的列的类型相匹配,并且为了使它与所有实体类一起工作,需要在运行时确定类型。
我使用反射来发现列的类型,但我不知道如何将我的“比较器”函数转换为适当的 Func<> 类型。因此,我设置了一个切换类型的 switch 语句。我想摆脱 switch 语句并分解出键类型。
我该怎么做呢?我的代码如下:
public override IEnumerable<T> GetSortedRecords<T>(IEnumerable<T> filteredRecords)
{
// The goal here is to allow for a developer to provide a method for sorting records,
// but to also provide a default method that will work with all instances of EntityObject.
// To that end, I believe it is necessary to use the fun fun DynamicMethod object.
// Note - check for ASC vs DESC
if (NumberOfSorts == 0)
return filteredRecords;
IOrderedEnumerable<T> sortedRecords = null;
for (int i = 0; i < NumberOfSorts; i++)
{
string propertyName = PropertyNames[ColumnSortOrder[i]];
PropertyInfo property = typeof(T).GetProperties().Single(p => p.Name == propertyName);
switch (property.PropertyType.Name)
{
// I want to get rid of these branches.
case "Int32":
Func<T, int> comparerInt32 = GetDefaultKeySelectorForProperty<T, Int32>(property);
sortedRecords = i == 0 ?
filteredRecords.OrderBy<T, int>(comparerInt32) :
sortedRecords.ThenBy<T, int>(comparerInt32);
break;
case "String":
Func<T, string> comparerString = GetDefaultKeySelectorForProperty<T, string>(property);
sortedRecords = i == 0 ?
filteredRecords.OrderBy<T, string>(comparerString) :
sortedRecords.ThenBy<T, string>(comparerString);
break;
default:
throw new NotImplementedException();
}
}
return sortedRecords;
}
delegate TKey GetDefaultKeySelectorForPropertyDelegate<T, TKey>(T t);
public Func<T, TKey> GetDefaultKeySelectorForProperty<T, TKey>(PropertyInfo property)
{
DynamicMethod method = new DynamicMethod("GetKeySelector", typeof(TKey), new Type[] { typeof(T) });
ILGenerator generator = method.GetILGenerator();
MethodInfo GetPropertyValue = property.GetGetMethod();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Callvirt, GetPropertyValue);
generator.Emit(OpCodes.Ret);
return ((GetDefaultKeySelectorForPropertyDelegate<T, TKey>)(method.CreateDelegate(typeof(GetDefaultKeySelectorForPropertyDelegate<T, TKey>)))).Invoke;
}