我有一個有十個欄位的介面,我經常把這個介面的兩個查詢表連接起來。大多數時候,所有的十個欄位都必須相等,但有時卻不是。現在,我通過大量的靜態擴展方法來解決這個問題,但是它們看起來都差不多,而且每增加一個變數,我都擔心會增加一個錯誤(錯誤的欄位等...)。
public static class MyJoins
{
public static IQueryable< T> JoinOnAll< T, TA, TB> (this IQueryable<TA> query, IQueryable< TB> otherQuery)
where TA : IMyInterface where TB : IMyInterface where T : class, IJoinInterface<TA, TB>, new()
{
return query.Join(otherQuery,
a => new { a.F1, a.F2, a.F3, a.F4, a.F5, a.F6, a.F7, a.F8, a.F9, a.F10 },
b => new { b.F1, b.F2, b.F3, b.F4, b.F5, b.F6, b.F7, b.F8, b.F9, b.F10 },
(t, p) => new T { AA = a, BB = b })。)
}
public static IQueryable< T> JoinOnAllButF2< T, TA, TB> (this IQueryable<TA> query, IQueryable< TB> otherQuery)
where TA : IMyInterface where TB : IMyInterface where T : class, IJoinInterface<TA, TB>, new()
{
return query.Join(otherQuery,
a => new { a.F1, a.F3, a.F4, a.F5, a.F6, a.F7, a.F8, a.F9, a.F10 },
b => new { b.F1, b.F3, b.F4, b.F5, b.F6, b.F7, b.F8, b.F9, b.F10 },
(t, p) => new T { AA = a, BB = b })。)
}
public static IQueryable< T> JoinOnAllButF4F7< T, TA, TB> (this IQueryable<TA> query, IQueryable< TB> otherQuery)
where TA : IMyInterface where TB : IMyInterface where T : class, IJoinInterface<TA, TB>, new()
{
return query.Join(otherQuery,
a => new { a.F1, a.F2, a.F3, a.F5, a.F6, a.F8, a.F9, a.F10 },
b => new { b.F1, b.F2, b.F3, b.F5, b.F6, b.F8, b.F9, b.F10 },
(t, p) => new T { AA = a, BB = b })。)
}
//還有很多這樣的例子。
}
是否有辦法將要比較的欄位作為一個引數傳遞?(我認為沒有) 是否有其他方法來解決這一大堆幾乎重復的代碼?
----,我將如何使用這個-------------------------
。我主要使用的方式是拆分查詢,連接它們,然后連接它們:
我主要使用的方式是拆分查詢,連接它們,然后連接它們。
IQueryable a = ......
IQueryable b = ......
var firstPart = a.Where(MyExpression).JoinOnAll(b);
var secondPart = a.Where(OtherExpression).JoinOnAllButF2(b);
var thirdPart = a.Where(AnotherExpression).JoinOnAllButF1F2F8(b);
var joinResult = firstPart.Concat(secondpart).Concat(thirdPart)。
var joinResultFiltered = joinResult.WHere(AndAnotherExpression);
return joinResultFiltered;
我有很多這樣的函式,但運算式和連接總是不同的。
補充資訊,因為在Commetns中有人問到:
介面基本上就是這樣。
這些介面基本上就是這樣的
public interface IMyInterface{
public string F1 {get;set; }
public string F2 {get; set; }
//直至F10。
}
uj5u.com熱心網友回復:
像這樣的情況如何:
public static class MyJoins
{
private sealed class ReplacementVisitor : ExpressionVisitor
{
public ReplacementVisitor(LambdaExpression source, Expression toFind, Expression replaceWith)
{
SourceParameters = source.Parameters;
ToFind = toFind;
ReplaceWith = replaceWith。
}
private IReadOnlyCollection<ParameterExpression> SourceParameters { get; }
private Expression ToFind { get; }
private Expression ReplaceWith { get; }
private Expression ReplaceNode(Expression node) => node == ToFind ? ReplaceWith : node;
protected override Expression VisitConstant(ConstantExpression node)/span> => ReplaceNode(node);
protected override Expression VisitBinary(BinaryExpression node)。
{
var result = ReplaceNode(node);
if (result == node) result = base.VisitBinary(node)。
return result。
}
protected override ExpressionVisitParameter(ParameterExpression node)
{
if (SourceParameters.Contains(node)) return ReplaceNode(node);
return SourceParameters.FirstOrDefault(p => p.Name == node.Name) ? ? node;
}
}
private static Expression<Func< T, object>> BuildJoinFields< T>(LambdaExpression fn) where T : IMyInterface
{
var p = Expression.Parameter(typeof(T), "p")。)
var visitor = new ReplacementVisitor(fn, fn.Parameters[0], p) 。
var body = visitor.Visit(fn.Body)。
return Expression.Lambda<Func<T, object>>(body, p)。
}
public static IQueryable<T> JoinOn<T, TA, TB> (
this IQueryable<TA> query,
IQueryable<TB> otherQuery。
Expression<Func<IMyInterface, object> > fieldsToJoinOn)
where TA : IMyInterface
where TB : IMyInterface,
where T : class, IJoinInterface<TA, TB>, new()
{
Expression<Func<TA, object>> aFields = BuildJoinFields<TA>(fieldToJoinOn)。
Expression<Func<TB, object>> bFields = BuildJoinFields<TB>(fieldToJoinOn);
return query.Join(otherQuery, aFields, bFields, (a, b) => new T { AA = a, BB = b }) 。
}
}
query.JoinOn(otherQuery, x => new { x.F1, x.F2, x.F3, ... })
盡管我不相信編譯器能夠推斷出型別引數的型別T。
uj5u.com熱心網友回復:
另一個解決方案。它不關心介面,連接鍵是基于外部型別。如果屬性沒有找到內部型別,它將拋出例外。
public static class QueryableExtensions
{
public interface IJoinInterface<TA, TB>
{
public TA AA { get; set; }
publicTB BB { get; set; }
}
class JoinHandler<TA, TB> : IJoinInterface<TA, TB>
{
public TA AA { get; set; }
publicTB BB { get; set; }
}
public static IQueryable<IJoinInterface< TA, TB>> JoinOn< TA, TB, TKey>(
this IQueryable<TA> outer,
IQueryable<TB> inner,
Expression<Func<TA, TKey>> joinKey)。
{
var innerParam = Expression.Parameter(typeof(TB), "inner") 。
var innerKey = BuildKey(joinKey, innerParam);
Expression<Func<TA, TB, IJoinInterface<TA, TB>> resultExpression = (a, b) => new JoinHandler<TA, TB> {AA=a, BB=b};
var queryExpression = Expression.Call(typeof(Queryable), nameof(Queryable.Join) 。
new[] { typeof(TA), typeof(TB), typeof(TKey), typeof(IJoinInterface< TA, TB>) }, outer. Expression, inner.Expression,
joinKey, innerKey, resultExpression)。
return outer.Provider.CreateQuery<IJoinInterface<TA, TB>>(queryExpression)。
}
private static LambdaExpression BuildKey(LambdaExpression source, ParameterExpression param)
{
var body = new MemberReplacer(source.Parameters[0], param).Visit(source.Body)。
return Expression.Lambda(body, param)。
}
class MemberReplacer : ExpressionVisitor public MemberReplacer(ParameterExpression sourceParam, ParameterExpression destParam)
{
SourceParam = sourceParam;
DestParam = destParam;
}
public ParameterExpression SourceParam { get; }
public ParameterExpression DestParam { get; }
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression == SourceParam)
{
if (DestParam.Type == SourceParam.Type)
return node.Update(DestParam)。
var destProp = DestParam.Type.GetProperty(node.Member.Name)。
if (destProp == null)
throw new ArgumentException($"Type '{DestParam. Type.Name}'沒有屬性'{node.Member.Name}'。")。)
return Expression.MakeMemberAccess(DestParam, destProp)。
}
return base.VisitMember(node)。
}
}
解決方案更接近于之前的答案,但更具有普遍性,不關心具體的介面實作。
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/310051.html
標籤:
上一篇:是否有高階函式來避免渲染時著火?
