我有以下代码:
using System;
using System.Linq;
using System.Linq.Expressions;
public class Program
{
public static void Main()
{
Descendant d = new Descendant();
d.TestMethod();
}
}
public class Base
{
protected void FigureItOut<TClass, TMember>(Expression<Func<TClass, TMember>> expr)
{
}
}
public class Descendant : Base
{
public void TestMethod()
{
FigureItOut(c => c.Name);
}
public String Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我收到此编译器错误消息:
The type arguments for method
'Base.FigureItOut<TClass,TMember>
(System.Linq.Expressions.Expression<System.Func<TClass,TMember>>)'
cannot be inferred from the usage. Try specifying the type arguments explicitly.
Run Code Online (Sandbox Code Playgroud)
如果我将对ImageItOut的调用更改为: …
我有这样的表情 Expression<Func<IInterface, object>>
我如何循环/遍历表达式内的所有表达式并查找使用Func(IInterface)输入参数的任何MethodCallExpression,以调用此类方法
inputParameter => inputParameter.MyMethod(typeof(SomeClass))
Run Code Online (Sandbox Code Playgroud)
或像这样的通用扩展方法
inputParameter => inputParameter.MyMethod<SomeClass>()
Run Code Online (Sandbox Code Playgroud)
如果找到两种方法之一,则需要通过Type。对于通用扩展方法,它将是通用参数,即类型,在另一个方法调用中,它是为方法调用中的参数提供的第一个参数
这两种方法的签名如下所示
object MyMethod(Type type)
T MyMethod<T>(this IInterface param) where T : class
Run Code Online (Sandbox Code Playgroud)
然后,使用两个方法调用之一中的类型查找另一个Expression<Func<IInterface, object>>,并将该方法调用替换为表达式的“内容”。
任何可以帮助我完成此工作的人吗?
搜索表达式以查找对两个方法之一的任何调用(如果找到),获取调用中使用的类型,并查找针对该类型注册的表达式(我在词典中找到它)并将方法调用替换为表达式正在执行的操作。
这是我要完成的示例。如果我有以下两个Expression<Func<IInterface, object>>声明为Bar1和Bar2类型
Bar1: x => new Foo1(x.MyMethod(typeof(Bar2)))
Bar2: x => new Foo2()
Run Code Online (Sandbox Code Playgroud)
解决/合并Func<IInterface, object>Bar1 的for最终看起来像这样
Bar1: x => new Foo1(new Foo2())
Run Code Online (Sandbox Code Playgroud)
该x.MyMethod(typeof(Bar2))类型BAR1登记在lambda通话将被替换为new Foo2()类型BAR2免费通话。
如果您需要更多信息来理解我的问题,请告诉我。
如何将以下lambda转换为表达式树?
source.Join(lookup, s => s.Id, l => l.Id, (s,l) => l)
Run Code Online (Sandbox Code Playgroud)
我认为除了resultSelector(s,l)=> l之外,我已经涵盖了所有内容.
这是我的代码..谢谢!
public static IQueryable<TLookup> GetLookupSource<T, TLookup, TKey>(this IQueryable<T> source, IQueryable<TLookup> lookup{
ParameterExpression s = Expression.Parameter(source.ElementType, "s");
Expression<Func<T, TKey>> outerKeySelector = Expression.Lambda<Func<T, TKey>>(Expression.PropertyOrField(s, "Id"), s);
ParameterExpression l = Expression.Parameter(lookup.ElementType, "l");
Expression<Func<TLookup, TKey>> innerKeySelector = Expression.Lambda<Func<TLookup, TKey>>(Expression.PropertyOrField(l, "Id"), l);
Expression<Func<T, TLookup, IQueryable<TLookup>>> resultSelector = null;//<---How to compose this
MethodInfo joinMethod = typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public).Where(m => m.Name == "Join" && m.GetParameters().Length == 5).First();
var genericJoinMethod = joinMethod.MakeGenericMethod(typeof(T), typeof(TLookup), typeof(TKey), typeof(IQueryable<TLookup>)); …Run Code Online (Sandbox Code Playgroud) 我有一个问题,想知道是否有办法吃蛋糕并吃掉它.
目前我有一个存储库和查询样式模式,我如何使用Linq2Sql,但我有一个问题,我看不到一个很好的方法来解决它.以下是问题的示例:
var someDataMapper = new SomeDataMapper();
var someDataQuery = new GetSomeDataQuery();
var results = SomeRepository.HybridQuery(someDataQuery)
.Where(x => x.SomeColumn == 1 || x.SomeColumn == 2)
.OrderByDescending(x => x.SomeOtherColumn)
.Select(x => someDataMapper.Map(x));
return results.Where(x => x.SomeMappedColumn == "SomeType");
Run Code Online (Sandbox Code Playgroud)
这里要注意的主要部分是Mapper,Query,Repository,然后是最后的where子句.我这样做是作为一个更大的重构的一部分,我们发现有很多类似的查询得到稍微不同的结果集,但然后将它们以相同的方式映射到特定于域的模型.因此,例如,取回a tbl_car然后将其映射到Car对象.因此,映射器基本上采用一种类型并吐出另一种类型,因此与选择中通常发生的情况完全相同:
// Non mapped version
select(x => new Car
{
Id = x.Id,
Name = x.Name,
Owner = x.FirstName + x.Surname
});
// Mapped version
select(x => carMapper.Map(x));
Run Code Online (Sandbox Code Playgroud)
因此,汽车映射器在所有区域上都可以重复使用,这些区域执行类似的查询,返回相同的最终结果,但在此过程中执行不同的位.但是我一直得到错误,说Map无法转换为SQL,这很好,因为我不希望它,但是我理解,因为它在表达式树中它会尝试转换它.
{"Method 'SomeData Map(SomeTable)' has no supported translation to SQL."}
Run Code Online (Sandbox Code Playgroud)
最后,返回并映射的对象在堆栈中进一步传递给其他对象使用,这使用Linq …
脚本
public class Element {
public int Id {get;set;}
}
public class ViewModel {
public IList<Element> Elements{get;set;}
}
Run Code Online (Sandbox Code Playgroud)
我有一个类型参数的方法Expression<Func<Element, int>>,看起来像m => m.Id
我想改造
m => m.Id (其中m是元素)
至
x => x.Elements[0].Id 其中x是ViewModel,0是"index"参数
我现在拥有的(当然是通用的,为了清晰起见我删除了通用部分)
public static class Helpers {
public static Expression<Func<ViewModel, int>> BuildExpressionArrayFromExpression(
this Expression<Func<Element, int>> expression,
ViewModel model,
int index = 0,
string bindingPropertyName = "Elements"//the name of the "List" property in ViewModel class
)
{
var parameter = Expression.Parameter(typeof(ViewModel), "x");
var viewModelProperty = model.GetType().GetProperty(bindingPropertyName);
Expression …Run Code Online (Sandbox Code Playgroud) 我有这个静态功能
public static object Create(Type t)
{
//unimportant
}
Run Code Online (Sandbox Code Playgroud)
我无法控制上面的上述功能,所以我无法改变它.问题是它不是通用的,所以我必须将返回的对象转换为某种类型.这个类型是由我调用该Create方法的另一个泛型类的约束提供的.
这是我到达的地方:
public static class Creator<T>
{
public static void Create()
{
var m = typeof(SomeClass).GetMethod("Create");
var p = Expression.Parameter(typeof(Type));
var e = Expression.Call(m, p);
//at this stage I want to create delegate for calling the 'Create' method,
//then pass typeof(T) as parameter, get returned object,
//and finally cast it to 'T'.
//for eg, I can do it like this:
var f = Expression.Lambda<Func<Type, object>>(e, p).Compile();
Func<T> mainThing …Run Code Online (Sandbox Code Playgroud) 假设我有这个lambda表达式,我想写一个表达式Tree:
query.Where(d => (allCk && d.FacilityId == facilityId) //1.
||
(!allCk && allSelected && d.FacilityId == facilityId && !ids.Contains(d.Id)) //2.
||
(!allCk && !allSelected && ids.Contains(d.Id))) //3.
Run Code Online (Sandbox Code Playgroud)
这就是我设法写它的原因:为简洁起见,我只展示第二个条件,这是最复杂的条件(!allCk && allSelected && d.FacilityId == facilityId && !ids.Contains(d.Id)).
private Expression<Func<Documents, bool>> GetDocumentsPredicate(
int facilityId, bool allCk, bool allSelected, List<int> ids)
{
ParameterExpression pe = Expression.Parameter(typeof(Documents), "d");
var listExpr1 = new List<Expression>();
listExpr1.Add(Expression.IsFalse(Expression.Constant(allCk))); //allCk
listExpr1.Add(Expression.Constant(allSelected)); //allSelected
var facilityParam = Expression.Constant(facilityId); //facility
Expression facilityIdProp = Expression.Property(pe, "FacilityId");
Expression facilityIdEql = Expression.Equal(facilityIdProp, facilityParam); …Run Code Online (Sandbox Code Playgroud) 我试图了解编译器推断行为.例如,从下面的代码片段中,编译的委托的运行时类型是Func<int>
Expression addExpr = Expression.Add(Expression.Constant(2), Expression.Constant(1));
LambdaExpression lambdaExpr1 = Expression.Lambda(addExpr, null);
var compiled = lambdaExpr1.Compile();
Run Code Online (Sandbox Code Playgroud)
但是下面的代码行不能编译.不确定这里有什么含糊不清的编译器隐式转换它Expression<Func<int>>并赋值给LambdaExpression类型
LambdaExpression lambdaExp2 = ()=>2+1;
Run Code Online (Sandbox Code Playgroud)
我可以猜到右边的lambda表达式的一个可能原因也可以匹配我的自定义委托的签名,在这种情况下,编译器无法推断委托类型.但同样的原因适用于我的初始代码段.为什么CLR(运行时)可以决定它可以是类型Func<int>.如果这是可能的并且通过运行时足够的推断那么为什么c#编译器也可以做同样的事情.
如果你有一个Type of Type Array而不是一个特定的数组类型,比如int [],那么如何生成一个表达式,该表达式可以快速获取长度,而无需执行整个属性获取malarkay.
例如在下面
ParameterExpression para3 = Expression.Parameter(typeof(int[]), "p3");
ParameterExpression para4 = Expression.Parameter(typeof(Array), "p4");
Type pt1 = para3.Type.GetElementType();
Type pt2 = para4.Type.GetElementType();
MethodInfo mArrayLength = Strong.Instance<Array>.Property<int>(a => a.Length).GetGetMethod();
Expression asdf5 = Expression.ArrayLength(para3);
Expression asdf6 = Expression.ArrayLength(para4);
Expression asdf7 = Expression.Call(para4, mArrayLength);
Run Code Online (Sandbox Code Playgroud)
mArrayLength只是Array类型的Length属性的get方法.
这里的表达式为asdf5,因为para5的类型为int [],但asdf6 不起作用,因为para6的类型只是Array类型.asdf7确实有效.
我想要的是有效地使用ldlen指令,它只需要一个Object,而不是调用一个方法.这仅仅是表达式树库的限制吗?
您可以使用反射编辑该字段,甚至可以编译表达式!但是尝试运行委托将导致操作可能破坏运行时异常的稳定性.
Array parr = new int[5];
Expression pArraylength = Expression.ArrayLength(para3);
pOperandFieldInfo.SetValue(pArraylength, para4);
Expression<Func<Array, int>> pexchanger = (Expression<Func<Array, int>>)Expression.Lambda(pArraylength, para4);
Func<Array, int> pFunc = pexchanger.Compile();
int pint = pFunc(parr);
Run Code Online (Sandbox Code Playgroud) 对于给定的搜索标签过滤器,预期结果是表示在给定标签ID列表中具有所有标签的实体的表达式.
Lambda可能将此表达为:
class Tag
{
public long TagId { get; set; }
}
class Taggable
{
ICollection<Tag> Tags { get; set; }
}
...
IEnumerable<long> searchTags = new List<long>() { 1, 2, 3 };
Func<Taggable, bool> filter = taggable => searchTags.All(qtag => taggable.Tags.Any(tag => tag.TagId == qtag));
Run Code Online (Sandbox Code Playgroud)
尝试将此表示为表达式树失败:
var tagParam = Expression.Parameter(typeof(Tag), "tag");
var taggableParam = Expression.Parameter(typeof(Taggable), "taggable");
MemberExpression tagsProperty = Expression.Property(taggableParam, "Tags");
ConstantExpression searchTagsConstant = Expression.Constant(searchTags);
var containsCall = Expression.Call(
typeof(Enumerable), "Contains",
new[] { typeof(long) },
searchTagsConstant,
Expression.Property(tagParam, "TagID") …Run Code Online (Sandbox Code Playgroud) c# ×10
expression-trees ×10
linq ×3
.net ×1
arrays ×1
asp.net-mvc ×1
cil ×1
expression ×1
generics ×1
lambda ×1
linq-to-sql ×1
sql ×1