13

I've ran into problem with extension method resolution. LINQ and MoreLINQ contain zip method, it was present in .NET since 4.0 version and was always in MoreLINQ library. But you can't use one of the implementation with nice-old extension method syntax. So this code won't compile

using MoreLinq;
using System.Linq;


var students = new [] { "Mark", "Bob", "David" };
var colors = new [] { "Pink", "Red", "Blue" };

students.Zip(colors, (s, c) => s + c );

Error:

The call is ambiguous between the following methods or properties: 
'MoreLinq.MoreEnumerable.Zip<string,string,string>
(System.Collections.Generic.IEnumerable<string>, 
System.Collections.Generic.IEnumerable<string>, System.Func<string,string,string>)' and 
'System.Linq.Enumerable.Zip<string,string,string>
(System.Collections.Generic.IEnumerable<string>, 
System.Collections.Generic.IEnumerable<string>, System.Func<string,string,string>)'

I've found good resolution for Concat method on string for MoreLINQ made by Jon Skeet at this post, but I'm not aware of good resolution for zip method.

NOTE: You can always use static method call syntax and it all works fine with

MoreEnumerable.Zip(students, colors, (s, c) => s + c )

but misses the point of extension syntax sugar a little bit. If you have lots of data transformation with LINQ and MoreLINQ calls - you don't want to use static method call in the middle.

Are there any better ways to resolve this ambiguity?

Community
  • 1
  • 1
Ilya Ivanov
  • 23,148
  • 4
  • 64
  • 90
  • 3
    Isn't there a 4.0-friendly version of MoreLINQ? (ie one that drops MoreLINQ's own `Zip` function) – AakashM Jan 18 '13 at 11:11
  • ... or just make one yourself, it's open source :) – Rawling Jan 18 '13 at 11:39
  • 3
    @AakashM no there isn't. You can see their issue regarding `zip` and .NET 4.0 here http://code.google.com/p/morelinq/issues/detail?id=60 and NoConflict resolution here https://gist.github.com/2869531 – Ilya Ivanov Jan 18 '13 at 11:53

5 Answers5

5

You can create a wrapper class with the same method, but diffrent name. It's a bit dirty, but if you really like to have extension syntax, that is the only way.

public static class MoreLinqWrapper
{
    public static IEnumerable<TResult> MlZip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector)
    {
        return MoreLinq.Zip(first, second, resultSelector);
    }
}
Vladimir Perevalov
  • 4,059
  • 18
  • 22
  • Yes, I also thought about it and wrote to Dennis answer. but I don't know if it is a better approach – Ilya Ivanov Jan 18 '13 at 10:53
  • It's ok until he has single `MoreLinq` call or he will use this fake method instead of `Zip`. The 1st case is not applicable - see the question text, the second case - well, I don't envy the person, who will have to support this code. I think, it will be hard to explain after year or two, why here's the call to `MlZip` (and what it is) instead of `Zip`. – Dennis Jan 18 '13 at 10:59
  • Dennis, usually I solve this problem by "Goto definition", and inside you'll immediately see the answer. Of course this is not a good solution. But comparing to having to replace lots of call to static syntax, I would choose this one. – Vladimir Perevalov Jan 18 '13 at 11:05
  • Ilya, here you should choose the least of two evils. I would make decision based on number of actual code lines I would have to change. I the number of usages is small, I would use static class syntax. Also, did you consider to just stop using MoreLinq? I was evaluating it, and found it not so good, but rather dirting the namespace. I only used 1-2 functions from it. And just copied them to my own extensions class. – Vladimir Perevalov Jan 18 '13 at 11:06
  • Ilya, as I said, I found only a couple of functions helpful, and all others were simply contaminating namespace. So I moved those 2-3 funcs to my own class and dereferenced MoreLinq. – Vladimir Perevalov Jan 18 '13 at 13:07
4

A way to make it compile would be:

var students = new[] { "Mark", "Bob", "David", "test" }.AsQueryable();
var colors = new[] { "Pink", "Red", "Blue" };

students
    .Zip(colors, (s, c) => s + c)
    .Dump();

The students object has to be converted to an IQueryable object.

Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
1

Update your morelinq, and from now

  • Use Zip for .NET 4.0 Zip
  • Use ZipShortest for MoreLinq Zip

Problem is fixed in 88c573f7

Atif Aziz
  • 36,108
  • 16
  • 64
  • 74
Nafeez Abrar
  • 1,045
  • 10
  • 27
  • 3
    As of Nov 2014 (version 1.1) MoreLinq still contains Zip; i.e. it appears this patch was not used, and the problem still happens. – Darren Cook Nov 07 '14 at 11:59
1

I ran into this the other day and I simply called the MoreLinq method directly.

MoreLinq.MoreEnumerable.Zip(students, colors, (s, c) => s + c);
Victor Wilson
  • 1,720
  • 1
  • 11
  • 22
0

Unfortunately, the static method call syntax is the only way here.

Dennis
  • 37,026
  • 10
  • 82
  • 150
  • 1
    Well, another way I can think of is to clone signature and create separate method with `Zipp` name, for example, that will call `MoreEnumerable.Zip`. But I don't think it's a better approach – Ilya Ivanov Jan 18 '13 at 10:50