如何在返回Expression的C#方法中调用返回Func<>的方法
原有实现
public static System.Linq.Expressions.Expression<Func<MetaMovie, bool>> IsEqual(MetaMovie other) { if (other.Id > 0) return m => other.Id == m.Id; return m => other.MetaSource == m.MetaSource && other.ExternalId == m.ExternalId; }
调用上述方法后变量的DebugView内容:
.Lambda #Lambda1<System.Func`2[com.cyberinternauts.all.MediaRecognizer.Models.Metas.MetaMovie,System.Boolean]>(com.cyberinternauts.all.MediaRecognizer.Models.Metas.MetaMovie $m) { (.Constant<com.cyberinternauts.all.MediaRecognizer.Models.Metas.MetaMovie+<>c__DisplayClass81_0>(com.cyberinternauts.all.MediaRecognizer.Models.Metas.MetaMovie+<>c__DisplayClass81_0>).other).MetaSource == $m.MetaSource && (.Constant<com.cyberinternauts.all.MediaRecognizer.Models.Metas.MetaMovie+<>c__DisplayClass81_0>(com.cyberinternauts.all.MediaRecognizer.Models.Metas.MetaMovie+<>c__DisplayClass81_0>).other).ExternalId == $m.ExternalId }
需求目标
希望创建一个Func<MetaMovie, bool> GetComparison(MetaMovie other)方法,供IsEqual方法调用,但无法成功集成。
尝试的实现
public static Func<MetaMovie, bool> GetComparison(MetaMovie other) { if (other.Id > 0) return m => other.Id == m.Id; return m => other.MetaSource == m.MetaSource && other.ExternalId == m.ExternalId; } public static Expression<Func<MetaMovie, bool>> IsEqual(MetaMovie other) { var param1 = Expression.Parameter(other.GetType(), "param1"); return Expression.Lambda<Func<MetaMovie, bool>>(Expression.Call(GetComparison(other).Method), param1); }
遇到的错误
IsEqual方法的return行报错:Static method requires null instance, non-static method requires non-null instance
错误原因与解决方法
错误本质是:你试图直接调用匿名委托的Method属性,但这些匿名方法是绑定到捕获变量的显示类实例的实例方法,调用时必须传入对应的实例作为第一个参数;更关键的是,这种方式会破坏表达式树的可解析性(比如EF无法翻译该表达式执行数据库查询)。
方案一:让GetComparison返回表达式树(推荐)
直接修改GetComparison返回表达式树,这样IsEqual可以直接复用其结果,完全保留原有逻辑的表达式树特性:
public static Expression<Func<MetaMovie, bool>> GetComparison(MetaMovie other) { if (other.Id > 0) return m => other.Id == m.Id; return m => other.MetaSource == m.MetaSource && other.ExternalId == m.ExternalId; } public static Expression<Func<MetaMovie, bool>> IsEqual(MetaMovie other) { return GetComparison(other); }
方案二:必须返回委托时,手动构建表达式树
如果业务限制必须让GetComparison返回编译后的委托,那么需要在IsEqual中手动构建等价的表达式树,避免直接调用委托方法:
public static Func<MetaMovie, bool> GetComparison(MetaMovie other) { if (other.Id > 0) return m => other.Id == m.Id; return m => other.MetaSource == m.MetaSource && other.ExternalId == m.ExternalId; } public static Expression<Func<MetaMovie, bool>> IsEqual(MetaMovie other) { var param = Expression.Parameter(typeof(MetaMovie), "m"); Expression body; if (other.Id > 0) { var otherId = Expression.Constant(other.Id); var paramId = Expression.Property(param, nameof(MetaMovie.Id)); body = Expression.Equal(otherId, paramId); } else { var otherMetaSource = Expression.Constant(other.MetaSource); var paramMetaSource = Expression.Property(param, nameof(MetaMovie.MetaSource)); var sourceEqual = Expression.Equal(otherMetaSource, paramMetaSource); var otherExternalId = Expression.Constant(other.ExternalId); var paramExternalId = Expression.Property(param, nameof(MetaMovie.ExternalId)); var idEqual = Expression.Equal(otherExternalId, paramExternalId); body = Expression.AndAlso(sourceEqual, idEqual); } return Expression.Lambda<Func<MetaMovie, bool>>(body, param); }
内容的提问来源于stack exchange,提问作者Master DJon
相关产品推荐
相关产品推荐

