tags:

views:

484

answers:

3

I am using Jon Skeet's very clever SmartEnumerable. I recommend checking it out if you haven't already seen it.

The class is defined :

public class SmartEnumerable<T> : IEnumerable<SmartEnumerable<T>.Entry>

The constructor is :

public SmartEnumerable(IEnumerable<T> enumerable)

and you use it by saying :

new SmartEnumerable<Cat>(myCats);  // where myCats is IEnumerable<Cat>

Now I'd really like to have the compiler infer I've got an array of cats and be able to just say :

new SmartEnumerable(myCats);

However this gives me a compiler error :

The type arguments for method 'MiscUtil.Collections.SmartEnumerable.SmartEnumerable(System.Collections.Generic.IEnumerable)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

I'm not clear exactly why this is. is there any way around it. Why can't it see I'm using IEnumerable<Cat> and infer from that. Can i change anythin to make it recognize the type I'm using?

I'd really like some way to construct a SmartEnumerable without having to specify the type - because I'm primarily using it for UI in ASP.NET MVC where I don't always have includes for the types and rely on var to get me a reference. I end up having to include types just to be able to use SmartEnumerable - which reduces its elegance.

Oh and I would have just emailed John directly but he'll probably reply faster here anyway :-)


<font color=white>skeet skeet skeet, jon, jon, jon, jon skeet, skeet jon, skeetster, skeetmeister</font>

+5  A: 

Try this code

public static class SmartEnumerable {
  public static SmartEnumerable<T> Create<T>(IEnumerable<T> source) {
    return new SmartEnumerable<T>(source);
  }
}

void Example() {
  IEnumerable<string> myCats = GetMyCats();
  var se = SmartEnumerable.Create(myCats);
}

Your code is failing because C# is not able to infer generic arguments on a constructor. But C# is more than capable of infering generic arguments on other methods.

In C# it's perfectly legal to have a class where the names only differ by the generic arguments. Foo and Foo<T> for example (under the hood they're actually different names). So the above sample will work for most scenarios. I personally use it whenever I define a generic class where the constructors take enough arguments to infer the full type.

JaredPar
trying to play some more, but still getting : Error 44 Using the generic type 'MiscUtil.Collections.SmartEnumerable<T>' requires '1' type arguments - on the myCats line
Simon_Weaver
What is the exact type of myCats?
JaredPar
IEnumerable<Cat> - well actually its of type 'InfoPanelEntry[]' but thats boring. I tried IEnumerable<string> myCats = null; to get that exact [compile time] error
Simon_Weaver
I updated my example to have a more full example.
JaredPar
@jaredpar - still no worky with jon's class. try downloading the SmartEnumerable class from the link at the top. your code may compile as it - but not in conjunction with the constructor and class definition i included above
Simon_Weaver
@Simon: This should definitely work, with Jared's extra code (I will include something like this in MiscUtil at some point soon; it clearly makes sense to use type inference here).
Jon Skeet
@jon i must be doing something stupid. i'm not stupid though - i moved out of Basingstoke while I could :-) live in LA now. couldnt get it to compile with the rest of your class, i'm not saying it doesnt work as is. i do like the extension method though because it parallels ToArray() and ToList()
Simon_Weaver
Will add it in MiscUtil and give an example in the usage page... easier than working out what's going wrong for you.
Jon Skeet
+5  A: 

I agree with JaredPar. I wanted to point out that you could also do an extension method:

public static SmartEnumerable<T> AsSmart<T>(this IEnumerable<T> source)
{
    return new SmartEnumerable<T>(source);
}

You would use it like so:

var smartEnumerable = myCats.AsSmart();

(The example sounds kind of funny)

Edit:

Per Jon Skeet, I renamed ToSmart to AsSmart.

Bryan Watts
this one works :) i like this one. makes me wonder about other ways of doing it. i was just trying to think about the generics aspects, so didn't even TRY to think out of the box. i guess you could probably do an explicit cast convertor too (?) but thats a little icky syntactically
Simon_Weaver
@bryan - our cats pretty smart so i can relate - http://ike.simonweaver.com. i've been using 'cat', 'dog', 'mouse' as variable names since i was about 8 years old despite never having had any of them as pets till now. i guess hamster is a bit long to type when you dont have intellisense
Simon_Weaver
This is nice too. Will include something similar. I'd still like a better name than "SmartEnumerable" but I can't think of anything...
Jon Skeet
@jon I cant think of anything fun, or even a good boring name but i'll keep thinking. also curious which of your methods of finding skeetposts led you to find mine... ;-) either way being able to do ToSmart() is invaluable for MVC UI coding when using var
Simon_Weaver
I think I'll call it AsSmartEnumerable rather than ToSmartEnumerable - it wraps it rather than immediately evaluating. Must check the implementation too.
Jon Skeet
(Of SmartEnumerable, I mean. The extension method is fine.)
Jon Skeet
Fumerable<T>
Svish
+2  A: 

A quick update - this is now available in MiscUtil itself. As per the example on the usage page:

// Old way
foreach (SmartEnumerable<string>.Entry entry in
                 new SmartEnumerable<string>(list))

// Better way
foreach (SmartEnumerable<string>.Entry entry in
                SmartEnumerable.Create(list))

// Best way (C# 3.0)
foreach (var entry in list.AsSmartEnumerable())
Jon Skeet
great! thanks jon. this is helping a TONNE for MVC UI work. really elegant solution. i always wondered why there was no way to get the index, but always just complained instead of fixing it. back to reading your book on my new Kindle 2 :-)
Simon_Weaver
My pleasure - and glad it's helping. I didn't know my book was available on the Kindle. Cool :) Hope you enjoy it.
Jon Skeet