Linq:OrderBy 动态嵌套 属性 可以为空
Linq: OrderBy dynamic nested property which can be null
这是我的代码,它通过 property
字符串生成 属性 个 T
对象。
// returning property as lambda from string
public static Func<T, object> GetPropertyFunc<T>(string property)
{
try
{
var parameter = Expression.Parameter(typeof(T), "obj");
Expression body = parameter;
foreach (var member in property.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
// conversion from Toutput to object
Expression converted = Expression.Convert(body, typeof(object));
return Expression.Lambda<Func<T, object>>(converted, parameter).Compile();
//return (Func<T, object>)Expression.Lambda(body, parameter).Compile();
}
catch (Exception ex)
{
throw ex;
}
}
接下来,我在这里使用它:
var orderParamFunc = PagedListHelper.GetPropertyFunc<T>(pagedListModel.OrderParameter.ParameterName);
IOrderedEnumerable<T> finalQuery = pagedListModel.OrderParameter.OrderAscending ? whereQuery.OrderBy(orderParamFunc) : whereQuery.OrderByDescending(orderParamFunc);
当 属性 不为空时效果很好。
我对示例有疑问:
property = "Customers.Dicts.DictValue"
in T object Customers
属性 可以是null Customers.Dicts
属性 也可以.
我应该在 GetPropertyFunc
方法中添加什么来检查 null?我不知道在哪里以及如何放置条件 != null
或 .HasValue
.
您需要在调用 GetPropertyFunc
方法之前检查这些属性的空值。这样,GetPropertyFunc
方法将 return 一个没有这些属性的 lambda。
老实说,我不确定您要做什么,只是您正在尝试创建一个您最终将在某处使用的查询。如果我们知道您的目标和意图,也许有更好的方法来实现您想要的。
如本 post 所示:
How to detect IsNull / NotNull when building dynamic LINQ expressions?
我建议更改 foreach 循环以检查构造为关于值类型的表达式的默认值 (null)。
这里有一点帮助构造值类型的默认值:
Programmatic equivalent of default(Type)
这是单元测试:
using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq.Expressions;
namespace TestProject1
{
[TestClass]
public class UnitTest1
{
class TestRefType2
{
public TestRefType2()
{
}
}
class TestRefType1
{
public TestRefType1()
{
}
public Guid VALUETYPE { get; set; }
public TestRefType2 REFTYPE { get; set; }
}
class MainType
{
public MainType()
{
}
public TestRefType1 REFTYPE { get; set; }
}
public static object GetDefault(Type type)
{
if (type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
// returning property as lambda from string
public static Func<T, object> GetPropertyFunc<T>(string property)
{
try
{
var parameter = Expression.Parameter(typeof(T), "obj");
Expression body = parameter;
foreach (var member in property.Split('.'))
{
var prop = Expression.PropertyOrField(body, member);
body = Expression.Condition(Expression.Equal(body, Expression.Default(body.Type)), Expression.Default(prop.Type), prop);
}
// conversion from Toutput to object
Expression converted = Expression.Convert(body, typeof(object));
return Expression.Lambda<Func<T, object>>(converted, parameter).Compile();
//return (Func<T, object>)Expression.Lambda(body, parameter).Compile();
}
catch (Exception ex)
{
throw ex;
}
}
[TestMethod]
public void TestMethod1()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.VALUETYPE");
object val = ex(t);
Assert.AreEqual(default(Guid), val);
}
[TestMethod]
public void TestMethod2()
{
MainType t = new MainType();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.VALUETYPE");
object val = ex(t);
Assert.AreEqual(default(Guid), val);
}
[TestMethod]
public void TestMethod3()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
var guid = Guid.NewGuid();
t.REFTYPE.VALUETYPE = guid;
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.VALUETYPE");
object val = ex(t);
Assert.AreEqual(guid, val);
}
[TestMethod]
public void TestMethod4()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE");
object val = ex(t);
Assert.AreNotEqual(default(TestRefType1), val);
}
[TestMethod]
public void TestMethod5()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.REFTYPE");
object val = ex(t);
Assert.AreEqual(default(TestRefType2), val);
}
[TestMethod]
public void TestMethod6()
{
MainType t = new MainType();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.REFTYPE");
object val = ex(t);
Assert.AreEqual(default(TestRefType2), val);
}
[TestMethod]
public void TestMethod7()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
var reftype2 = new TestRefType2();
t.REFTYPE.REFTYPE = reftype2;
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.REFTYPE");
object val = ex(t);
Assert.AreEqual(reftype2, val);
}
}
}
这是我的代码,它通过 property
字符串生成 属性 个 T
对象。
// returning property as lambda from string
public static Func<T, object> GetPropertyFunc<T>(string property)
{
try
{
var parameter = Expression.Parameter(typeof(T), "obj");
Expression body = parameter;
foreach (var member in property.Split('.'))
{
body = Expression.PropertyOrField(body, member);
}
// conversion from Toutput to object
Expression converted = Expression.Convert(body, typeof(object));
return Expression.Lambda<Func<T, object>>(converted, parameter).Compile();
//return (Func<T, object>)Expression.Lambda(body, parameter).Compile();
}
catch (Exception ex)
{
throw ex;
}
}
接下来,我在这里使用它:
var orderParamFunc = PagedListHelper.GetPropertyFunc<T>(pagedListModel.OrderParameter.ParameterName);
IOrderedEnumerable<T> finalQuery = pagedListModel.OrderParameter.OrderAscending ? whereQuery.OrderBy(orderParamFunc) : whereQuery.OrderByDescending(orderParamFunc);
当 属性 不为空时效果很好。 我对示例有疑问:
property = "Customers.Dicts.DictValue"
in T object Customers
属性 可以是null Customers.Dicts
属性 也可以.
我应该在 GetPropertyFunc
方法中添加什么来检查 null?我不知道在哪里以及如何放置条件 != null
或 .HasValue
.
您需要在调用 GetPropertyFunc
方法之前检查这些属性的空值。这样,GetPropertyFunc
方法将 return 一个没有这些属性的 lambda。
老实说,我不确定您要做什么,只是您正在尝试创建一个您最终将在某处使用的查询。如果我们知道您的目标和意图,也许有更好的方法来实现您想要的。
如本 post 所示:
How to detect IsNull / NotNull when building dynamic LINQ expressions?
我建议更改 foreach 循环以检查构造为关于值类型的表达式的默认值 (null)。
这里有一点帮助构造值类型的默认值:
Programmatic equivalent of default(Type)
这是单元测试:
using System;
using System.Text;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq.Expressions;
namespace TestProject1
{
[TestClass]
public class UnitTest1
{
class TestRefType2
{
public TestRefType2()
{
}
}
class TestRefType1
{
public TestRefType1()
{
}
public Guid VALUETYPE { get; set; }
public TestRefType2 REFTYPE { get; set; }
}
class MainType
{
public MainType()
{
}
public TestRefType1 REFTYPE { get; set; }
}
public static object GetDefault(Type type)
{
if (type.IsValueType)
{
return Activator.CreateInstance(type);
}
return null;
}
// returning property as lambda from string
public static Func<T, object> GetPropertyFunc<T>(string property)
{
try
{
var parameter = Expression.Parameter(typeof(T), "obj");
Expression body = parameter;
foreach (var member in property.Split('.'))
{
var prop = Expression.PropertyOrField(body, member);
body = Expression.Condition(Expression.Equal(body, Expression.Default(body.Type)), Expression.Default(prop.Type), prop);
}
// conversion from Toutput to object
Expression converted = Expression.Convert(body, typeof(object));
return Expression.Lambda<Func<T, object>>(converted, parameter).Compile();
//return (Func<T, object>)Expression.Lambda(body, parameter).Compile();
}
catch (Exception ex)
{
throw ex;
}
}
[TestMethod]
public void TestMethod1()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.VALUETYPE");
object val = ex(t);
Assert.AreEqual(default(Guid), val);
}
[TestMethod]
public void TestMethod2()
{
MainType t = new MainType();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.VALUETYPE");
object val = ex(t);
Assert.AreEqual(default(Guid), val);
}
[TestMethod]
public void TestMethod3()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
var guid = Guid.NewGuid();
t.REFTYPE.VALUETYPE = guid;
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.VALUETYPE");
object val = ex(t);
Assert.AreEqual(guid, val);
}
[TestMethod]
public void TestMethod4()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE");
object val = ex(t);
Assert.AreNotEqual(default(TestRefType1), val);
}
[TestMethod]
public void TestMethod5()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.REFTYPE");
object val = ex(t);
Assert.AreEqual(default(TestRefType2), val);
}
[TestMethod]
public void TestMethod6()
{
MainType t = new MainType();
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.REFTYPE");
object val = ex(t);
Assert.AreEqual(default(TestRefType2), val);
}
[TestMethod]
public void TestMethod7()
{
MainType t = new MainType();
t.REFTYPE = new TestRefType1();
var reftype2 = new TestRefType2();
t.REFTYPE.REFTYPE = reftype2;
Func<MainType, object> ex = GetPropertyFunc<MainType>("REFTYPE.REFTYPE");
object val = ex(t);
Assert.AreEqual(reftype2, val);
}
}
}