我试图开始a little Github open-source project.。它有助于创建可以Expression<Func<ABusinessObject, bool>>
返回或编译为Func<ABusinessObject, bool>
的过滤器。
目前,我必须以下列方式定义我的对象,包括, int>
以指定属性类型:
new EqualitySieve<ABusinessObject, int>()
.ForProperty(x=>x.AnInt)
.ForValues("1, 2, 3");
它包含一个名为AcceptableValues
的属性,它与我的代码中其他位置的属性TPropertyType
的类型相同。)。我使用它来让用户看到Sieve当前可以接受哪些值。
我希望能够删除, int>
部分,并按以下方式编写此代码:
new EqualitySieve<ABusinessObject>()
.ForProperty(x=>x.AnInt)
.ForValues("1, 2, 3");
让AcceptableValues
列表的类型为int
推断。
允许我执行此操作的代码如下,几乎完全基于this SO question。
/// <param name="propertyLambda">A lambda that indicates the property that we'd like to filter on.</param>
/// <remarks>
/// This is almost entirely possible due to the excellent answer on:
/// https://stackoverflow.com/questions/671968/retrieving-property-name-from-lambda-expression
/// </remarks>
public EqualitySieve<TTypeOfObjectToFilter, TPropertyType> ForProperty(Expression<Func<TTypeOfObjectToFilter, TPropertyType>> propertyLambda)
{
Type typePropertyShouldBeFrom = typeof(TTypeOfObjectToFilter);
var member = propertyLambda.Body as MemberExpression;
if (member == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.",propertyLambda));
var propInfo = member.Member as PropertyInfo;
if (propInfo == null)
throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.",propertyLambda));
Debug.Assert(propInfo.ReflectedType != null, "propInfo.ReflectedType != null");
if (typePropertyShouldBeFrom != propInfo.ReflectedType &&
!typePropertyShouldBeFrom.IsSubclassOf(propInfo.ReflectedType))
throw new ArgumentException(string.Format("Expresion '{0}' refers to a property that is not from type {1}.",propertyLambda,
typePropertyShouldBeFrom));
PropertyToFilter = propInfo;
return this;
}
有一种优雅的方式来进行转换吗?我并不担心API,因为该项目处于pre-alpha状态,但如果我能保留AcceptableValues
列表并确保它与属性保持相同类型,那就太棒了。
注意:从技术上讲,任何Sieve都需要在属性上运行,我也可以删除ForProperty
并将lambda表达式放在构造函数中,如果这样做的话帮助迈向更优雅的解决方案。
PS。在我想要学习的同时,也可以随意提交拉取请求(这是issue #27),我很乐意为您提供项目贡献者的信任。
答案 0 :(得分:1)
即使我无法提供任何结论,也许我可以帮助指出正确的方向。
重点在于您需要使用泛型方法,这些方法可以推断类型(泛型类不能)。也就是说,如果您有这样的方法:
public class Foo
{
public void Something<T>(T value) { }
}
然后你可以简单地编写new Foo().Something("a string")
,编译器将推断T
是string
。但如果泛型是在类级别:
public class Foo<T>
{
public void Something(T value) { }
}
然后,您必须明确指定T
,如new Foo<string>().Something("a string")
。
应用上述内容,我会说你需要的是一个&#34; builder&#34;构造中间值的类。鉴于你想要的语法,我建议如下:
// sieve will be of type "EqualitySieve<ABusinessObject, int>"
var sieve = new EqualitySieveBuilder<ABusinessObject>()
.ForProperty(x=>x.AnInt)
.ForValues("1, 2, 3");
EqualitySieveBuilder<T>
类是一种中间类,其函数返回实际的EqualitySieve<T, TProperty>
个实例:
public class EqualitySieveBuilder<T>
{
public EqualitySieve<T, TProperty> ForProperty<TProperty>(
Expression<Func<T, TProperty>> propertyExpression)
{
return new EqualitySieve<T, TProperty>()
.ForProperty(propertyExpression);
}
}
然后,您可以通过这种方法获得更多,添加多个接口,封装构建最终实例的各个中间阶段。