How to perform Dynamic Join using LINQ

前端 未结 1 435
没有蜡笔的小新
没有蜡笔的小新 2021-01-13 18:59

I have two collections. Each collection contains instances of a specific type. I need to join these two collections using one of the properties of the instances from each of

1条回答
  •  耶瑟儿~
    2021-01-13 19:09

    The first clue to solving this is to re-write your join using lamda syntax for the Join

    var query = fMyTranList.Join(fYourTranList,
                   a => a.MyAmountGBP, 
                   b => b.YourAmountGBP, 
                   (c,d) => new
                        {
                            MyId = c.Id,
                            YourId = d.Id,
                            MyAmtUSD = c.MyAmountUSD,
                            MyAmtGBP = c.MyAmountGBP,
                            YourAmtUSD = d.YourAmountUSD,
                            YourAmtGBP = d.YourAmountGBP
                        });
    

    Live: http://rextester.com/OGC85986

    Which should make it clear that making this dynamic would require passing in to your "generic" join function 3 functions

    1. a Func function for selecting the key for LHS
    2. a Func function for selecting the key for RHS
    3. a Func function for selecting the result

    So from there you could use reflection to make this all a bit dynamic:

    public static class DynamicJoinExtensions
    {
        public static IEnumerable DynamicJoin(this IEnumerable myTran, IEnumerable yourTran, params Tuple[] keys)
        {
            var outerKeySelector = CreateFunc(keys.Select(k => k.Item1).ToArray());
            var innerKeySelector = CreateFunc(keys.Select(k => k.Item2).ToArray());
    
            return myTran.Join(yourTran, outerKeySelector, innerKeySelector, (c, d) => new
            {
                MyId = c.Id,
                YourId = d.Id,
                MyAmtUSD = c.MyAmountUSD,
                MyAmtGBP = c.MyAmountGBP,
                YourAmtUSD = d.YourAmountUSD,
                YourAmtGBP = d.YourAmountGBP
            }, new ObjectArrayComparer());
        }
    
        private static Func CreateFunc(string[] keys)
        {
            var type = typeof(TObject);
            return delegate(TObject o)
            {
                var data = new object[keys.Length];
                for(var i = 0;i
        {
    
            public bool Equals(object[] x, object[] y)
            {
                return x.Length == y.Length
                       && Enumerable.SequenceEqual(x, y);
            }
    
            public int GetHashCode(object[] o)
            {
                var result = o.Aggregate((a, b) => a.GetHashCode() ^ b.GetHashCode());
                return result.GetHashCode();
            }
        }
    }
    

    Usage to match your example would then be:

    var query = fMyTranList.DynamicJoin(fYourTranList, 
                   Tuple.Create("MyAmountGBP", "YourAmountGBP"));
    

    but as the keys are params you can pass as many as you like:

    var query = fMyTranList.DynamicJoin(fYourTranList, 
                  Tuple.Create("MyAmountGBP", "YourAmountGBP"), 
                  Tuple.Create("AnotherMyTranProperty", "AnotherYourTranProperty"));
    

    Live example: http://rextester.com/AAB2452

    0 讨论(0)
提交回复
热议问题