- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
我使用一些被序列化的强类型表达式,以允许我的 UI 代码具有强类型排序和搜索表达式。这些是类型 Expression<Func<TModel,TProperty>>
并按原样使用:SortOption.Field = (p => p.FirstName);
.对于这个简单的案例,我已经让它完美地工作了。
我用来解析“FirstName”属性的代码实际上是在我们使用的第三方产品中重用了一些现有功能,并且效果很好,直到我们开始使用深层嵌套的属性( SortOption.Field = (p => p.Address.State.Abbreviation);
)。此代码在支持深层嵌套属性的需要方面有一些非常不同的假设。
至于这段代码的作用,我不是很理解,与其修改那段代码,我想我应该从头开始编写这个功能。但是,我不知道有什么好的方法可以做到这一点。我怀疑我们可以做一些比执行 ToString() 和执行字符串解析更好的事情。那么,什么是处理琐碎和深层嵌套情况的好方法呢?
要求:
p => p.FirstName
我需要一串 "FirstName"
.p => p.Address.State.Abbreviation
我需要一串 "Address.State.Abbreviation"
虽然这对我的问题的回答并不重要,但我怀疑我的序列化/反序列化代码可能对将来发现此问题的其他人有用,所以它在下面。同样,这段代码对问题并不重要——我只是认为它可能对某人有所帮助。注意 DynamicExpression.ParseLambda
来自 Dynamic LINQ东西和Property.PropertyToString()
是关于这个问题的。
/// <summary>
/// This defines a framework to pass, across serialized tiers, sorting logic to be performed.
/// </summary>
/// <typeparam name="TModel">This is the object type that you are filtering.</typeparam>
/// <typeparam name="TProperty">This is the property on the object that you are filtering.</typeparam>
[Serializable]
public class SortOption<TModel, TProperty> : ISerializable where TModel : class
{
/// <summary>
/// Convenience constructor.
/// </summary>
/// <param name="property">The property to sort.</param>
/// <param name="isAscending">Indicates if the sorting should be ascending or descending</param>
/// <param name="priority">Indicates the sorting priority where 0 is a higher priority than 10.</param>
public SortOption(Expression<Func<TModel, TProperty>> property, bool isAscending = true, int priority = 0)
{
Property = property;
IsAscending = isAscending;
Priority = priority;
}
/// <summary>
/// Default Constructor.
/// </summary>
public SortOption()
: this(null)
{
}
/// <summary>
/// This is the field on the object to filter.
/// </summary>
public Expression<Func<TModel, TProperty>> Property { get; set; }
/// <summary>
/// This indicates if the sorting should be ascending or descending.
/// </summary>
public bool IsAscending { get; set; }
/// <summary>
/// This indicates the sorting priority where 0 is a higher priority than 10.
/// </summary>
public int Priority { get; set; }
#region Implementation of ISerializable
/// <summary>
/// This is the constructor called when deserializing a SortOption.
/// </summary>
protected SortOption(SerializationInfo info, StreamingContext context)
{
IsAscending = info.GetBoolean("IsAscending");
Priority = info.GetInt32("Priority");
// We just persisted this by the PropertyName. So let's rebuild the Lambda Expression from that.
Property = DynamicExpression.ParseLambda<TModel, TProperty>(info.GetString("Property"), default(TModel), default(TProperty));
}
/// <summary>
/// Populates a <see cref="T:System.Runtime.Serialization.SerializationInfo"/> with the data needed to serialize the target object.
/// </summary>
/// <param name="info">The <see cref="T:System.Runtime.Serialization.SerializationInfo"/> to populate with data. </param>
/// <param name="context">The destination (see <see cref="T:System.Runtime.Serialization.StreamingContext"/>) for this serialization. </param>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
// Just stick the property name in there. We'll rebuild the expression based on that on the other end.
info.AddValue("Property", Property.PropertyToString());
info.AddValue("IsAscending", IsAscending);
info.AddValue("Priority", Priority);
}
#endregion
}
最佳答案
诀窍是:任何这种形式的表达...
obj => obj.A.B.C // etc.
...实际上只是一堆嵌套的 MemberExpression
对象。
首先你有:
MemberExpression: obj.A.B.C
Expression: obj.A.B // MemberExpression
Member: C
正在评估 Expression
以上为MemberExpression
给你:
MemberExpression: obj.A.B
Expression: obj.A // MemberExpression
Member: B
最后,那个(在“顶部”)你有:
MemberExpression: obj.A
Expression: obj // note: not a MemberExpression
Member: A
所以很明显解决这个问题的方法是检查 Expression
MemberExpression
的属性直到它本身不再是 MemberExpression
为止.
更新:您的问题似乎有更多的变化。可能是您有一些 看起来 像 Func<T, int>
的 lambda。 ...
p => p.Age
...但是实际上是Func<T, object>
;在这种情况下,编译器会将上面的表达式转换为:
p => Convert(p.Age)
针对此问题进行调整实际上并不像看起来那么困难。查看我更新的代码,了解一种处理方法。请注意,通过抽象代码以获得 MemberExpression
进入它自己的方法(TryFindMemberExpression
),这种方法保留了GetFullPropertyName
方法相当干净,允许您在将来添加额外的检查——如果,也许,您发现自己面临一个您最初没有考虑过的新场景——而不必费力费力代码。
为了说明:这段代码对我有用。
// code adjusted to prevent horizontal overflow
static string GetFullPropertyName<T, TProperty>
(Expression<Func<T, TProperty>> exp)
{
MemberExpression memberExp;
if (!TryFindMemberExpression(exp.Body, out memberExp))
return string.Empty;
var memberNames = new Stack<string>();
do
{
memberNames.Push(memberExp.Member.Name);
}
while (TryFindMemberExpression(memberExp.Expression, out memberExp));
return string.Join(".", memberNames.ToArray());
}
// code adjusted to prevent horizontal overflow
private static bool TryFindMemberExpression
(Expression exp, out MemberExpression memberExp)
{
memberExp = exp as MemberExpression;
if (memberExp != null)
{
// heyo! that was easy enough
return true;
}
// if the compiler created an automatic conversion,
// it'll look something like...
// obj => Convert(obj.Property) [e.g., int -> object]
// OR:
// obj => ConvertChecked(obj.Property) [e.g., int -> long]
// ...which are the cases checked in IsConversion
if (IsConversion(exp) && exp is UnaryExpression)
{
memberExp = ((UnaryExpression)exp).Operand as MemberExpression;
if (memberExp != null)
{
return true;
}
}
return false;
}
private static bool IsConversion(Expression exp)
{
return (
exp.NodeType == ExpressionType.Convert ||
exp.NodeType == ExpressionType.ConvertChecked
);
}
用法:
Expression<Func<Person, string>> simpleExp = p => p.FirstName;
Expression<Func<Person, string>> complexExp = p => p.Address.State.Abbreviation;
Expression<Func<Person, object>> ageExp = p => p.Age;
Console.WriteLine(GetFullPropertyName(simpleExp));
Console.WriteLine(GetFullPropertyName(complexExp));
Console.WriteLine(GetFullPropertyName(ageExp));
输出:
FirstName
Address.State.Abbreviation
Age
关于c# - 从 Expression<Func<TModel,TProperty>> 获取字符串形式的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2789504/
我在等待异步功能完成时苦苦挣扎。特别是,我发现这两种方法在测试继续之前等待异步函数完成,但不知道其中的区别(如果有区别的话):。我的目标是在实际测试开始之前等待bepreEach()块中的两个异步函数
我在等待异步功能完成时苦苦挣扎。特别是,我发现这两种方法在测试继续之前等待异步函数完成,但不知道其中的区别(如果有区别的话):。我的目标是在实际测试开始之前,在beforeEach()块中等待两个Ja
为什么是Func<>从 Expression> 创建通过 .Compile() 比仅使用 Func<> 慢得多直接声明? 我刚从使用 Func 更改为直接声明为从 Expression> 创建的一个在
我正在创建一个 Validator类(class)。我正在尝试实现 Linq SelectMany我的验证器的扩展方法能够使用 Linq 查询组合表达式并验证最终结果,即使基础值发生变化也是如此。 下
function sum(a) { let currentSum = a; function f(b) { currentSum += b; return f; }
我只知道i = i++;是未定义的行为,但是如果一个表达式中调用了两个或多个函数,并且所有功能是一样的。是未定义吗?例如: int func(int a) { std::cout << a <
我如何定义一个对象,以便作用于它的任何函数都作用于它的一个字段?这可能吗? class Mydata(object): def __init__(self, val): sel
这个问题一直很有趣,尽管它不一定很整洁。我有以下代码: import random def d(m): return random.randint(1, m) print(3*d(6)) 这将
能否请您解释一下使用 func.apply(null, arr) 的区别?和 func.apply(this, arr)在下面的代码示例中? var Foo = function() { fu
我想收集/运行任务,然后对它们执行 Task.WhenAll。 var tasks = new List(); foreach (var thing in things) { tasks.Add(
我有以下代码: static Func s_objToString = (x) => x.ToString(); static Func s_stringToString = s_objToStrin
相关主题: Create Expression> dynamically 我在互联网上搜索但所有样本都解释了 Expression来自 T ? 谢谢 编辑 1) T输入我的代码在运行时确定,例如我想用
我正在尝试使用 LinqKit 动态生成 linqtosql 查询.在将表达式发送到 LinqKit 之前,我想检查要为预测添加的字段。所以我想出了一些想法,比如 Expression> GetPr
我遇到了一些麻烦,我写了一个 Func,IDE 不喜欢我在 Func 体内调用 Func ,我不太明白为什么,因为如果我将这个确切的代码放在方法体中,并使用相同的返回类型和参数,那么它就可以工作。 代
我现在正在学习使用 Class 语法来创建 React 组件,请注意我现在必须声明这样的方法: class Foo extends React.Component { ... bar
下面两种说法有区别吗?他们都工作。 if ( ((Func)(()=>true))() ) { .... }; if ( new Func(()=>true)()) { .... }; 最佳答案 不,
这个问题在这里已经有了答案: Difference between func() and (*this).func() in C++ (4 个答案) 关闭 6 年前。 如果我有一个带有虚函数而没有自
主要问题是“是否可以将任何类型的 func 作为参数传递以及如何传递?”。我正在学习 Go 并且想像这样制作我自己的异步包装函数: func AsyncFunc(fn func(), args ...
有没有简单的转换方法 Expression> 到 Expression> T从哪里继承自TBase? 最佳答案 只要 T 派生自 TBase,您就可以使用原始表达式的主体和参数直接创建所需类型的表达式
我有以下方法,其中 T 在 Func 中使用: public void DoSomething(string someString, Func someMethod) { if(some
我是一名优秀的程序员,十分优秀!