Introducing Elevate

The past few weeks, a few other SRT Solutions developers and I have been working on a new open source library called Elevate. We went public with the source on CodePlex this weekend, and although we’re still in the early stages of development, I already rely on many of the functional programming features of the library in my day to day coding. So, without further ado, I’d like to formally announce the Elevate project.

 

What Is Elevate?

Let’s face it, no library has it all, and the BCL is no exception. If you’re anything like me, then you occasionally find yourself re-writing some utility methods over and over again for each project that you work on. Even though you know it’s wrong, you probably re-invent the wheel from time to time for “simple” things. Maybe you carry around your own “MyUtilities.cs” file from project to project. Either way, in the back of your mind, you know that there has to be a better way.

For C++ programmers, this void is filled with Boost. Boost contains a lot of functionality that is missing from the C++ STL for one reason or another. It’s a great library for C++ development. But what about us poor C# developers?

That’s where Elevate comes in. Elevate is a Boost-like library for .NET. Our goal at SRT Solutions is to capture the things that we think are missing from the BCL and put them in Elevate so that we can share them between our project groups and the rest of the world. By devoting some of our weekly learning time to add these common bits of code to Elevate, we can save ourselves, our clients, and hopefully other .NET developers time and money.

 

What do we have so Far?

We can’t add everything overnight, so to start off, we’re focusing on functional programming concepts. We’ve already taken some of the more useful methods and classes from languages like F#, Ruby, and Haskell and added them to our own collection of useful C# utilities. Here are some of the highlights below:

 

Building sequences:

[Test]
public void MixingAndMatching()
{
    //if you have a couple sequences of values
    var first = Seq.Build("alpha", "beta");
    var second = Seq.Build("delta", "epsilon");
 
    //you can combine them along with some other values to create a new sequence
    var result = Seq.Build(first, "gamma", second, "zeta");
 
    var expected = Seq.Build("alpha", "beta", "gamma", "delta", "epsilon", "zeta");
    Assert.AreEqual(expected, result);
}
 
[Test]
public void Through()
{
    //if we want to easily generate a sequence of incrementing numbers,
    //we can do it like this
    IEnumerable<int> numbers = 1.Through(15);
 
    var expected = Seq.Build(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
    Assert.AreEqual(expected, numbers);
}

 

“LINQ Extensions”:

[Test]
public void SelectWithIndex()
{
    //given a sequence of values
    var values = 10.Through(50, 10);
 
    //we can apply a selector function to each element based
    //on the element's value and it's index
    var result = values.SelectWithIndex((index, value) =>
                                             value / (index + 1));
 
    var expected = Seq.Build(10, 10, 10, 10, 10);
    Assert.AreEqual(expected, result);
}
 
[Test]
public void Chunk()
{
    //given a sequence
    var sequence = 1.Through(20);
 
    //we can split the sequence into a sequence of "chunks" that
    //are each a specific length
    var chunks = sequence.Chunk(5);
 
    var expectedChunks = 
        Seq.Build<IEnumerable<int>>( 
            1.Through(5).ToList(),
            6.Through(10).ToList(),
            11.Through(15).ToList(),
            16.Through(20).ToList());
 
    Assert.AreEqual(expectedChunks, chunks);
}
 
[Test]
public void Select2()
{
    //given two sequences
    var one = 0.Through(5);
    var two = 2.Through(12, 2);
 
    //we use Select2 to walk the sequences in parallel and apply a
    //selector function
    var result = one.Select2(two, (elementFromFirst, elementFromSecond) => 
            elementFromFirst * elementFromSecond);
 
    var expected = Seq.Build(0, 4, 12, 24, 40, 60);
    Assert.AreEqual(expected, result);
}

 
 
Pattern Matching:
 
 
[Test]
public void PatternMatchingWithFunctions()
{
    //given a value
    var value = "alpha";
 
    //we can start a pattern match like this
    var result = value.Match()
        //causes the pattern match to return "empty" if value is null or empty
        .With(string.IsNullOrEmpty, stringValue => "empty")
        //match any string containing "a"
        .With(stringValue => value.Contains("a"), stringValue => "contains a!")
        .EndMatch();
 
    Assert.AreEqual("contains a!", result);
}
[Test]
public void EasierTuplePatternMatching()
{
    //given a tuple
    Tuple<string, int> tuple = Tuple.Create("Da Bears", 2);
 
    //We can avoid having to specify the arguments explicitly for the
    //match portion of the predicate like this
    var result = tuple.Match()
        .WithSecond(1, (teamName, wins) => wins + 1)
        .WithFirst("Da Bears", (teamName, wins) => wins)
        .EndMatch();
 
    Assert.AreEqual(result, 2);
}

 

Option Types:

 

[Test]
public void OptionTypesCanContainValues()
{
    //given a value
    var value = 10;
 
    //we can wrap it in an option type like this
    Option<int> option = Option.Some(value);
 
    Assert.IsTrue(option.IsSome);
    Assert.IsFalse(option.IsNone);
    Assert.AreEqual(10, option.Value);
}
[Test]
public void MultipleOpertionsWithOptionTypes()
{
    //say we have a few functions that may or may not return a value.
    Func<int, Option<int>> divideIfEven = value =>
        ((value % 2) == 0) ? Option.Some(value / 2) : Option<int>.None;
 
    Func<int, Option<int>> subtractIfDivisibleByThree = value =>
        ((value % 3) == 0) ? Option.Some(value - 3) : Option<int>.None;
 
    Func<int, Option<int>> multiplyIfOdd = value =>
        ((value % 2) != 0) ? Option.Some(value * 2) : Option<int>.None;
 
    //we can chain these operations together like this:
    Option<int> result =
        divideIfEven(36)
        .Select(subtractIfDivisibleByThree)
        .Select(multiplyIfOdd);
 
 
    //the result of one carries on to the next to yield the expected result
    Assert.IsTrue(result.IsSome);
    Assert.AreEqual(30, result.Value);
}

 

These are just a few samples of the things you can do with Elevate, but there is a lot more to play around with in the actual library. Hopefully, you’re convinced that there are already a number of interesting functional programming features.

 

Moving Forward

If you’re interested in the above samples, head on over to http://elevate.codeplex.com and check out the source. All of the above samples are copied right out of the “Elevate.Guide” test project. We wrote this project with the goal that someone who has no experience with Elevate can get up and running quickly just by reading through it.

Over the next few weeks, I will try to post about some of the features in Elevate in more detail. If you’re a C# programmer interested in functional programming, a functional programming guru who wants to see examples of functional programming in C#, or simply someone interested in seeing cool and useful language extensions, stay tuned for more detailed posts.

Finally, we would love to hear any feedback (good or bad) and any feature requests that you might have. There are a number of ways to get in contact with us. You can submit comments below, start a discussion or submit a review on the CodePlex page, send an email through CodePlex, or send me a tweet (my username is ChrisMarinos on CodePlex and twitter). Also, speaking of Twitter, be sure to follow @elevateproject for updates!

Update: Check out our GoogleGroup at http://groups.google.com/group/ElevateProject!

Published 19 August 2009 12:27 AM by cmarinos

Comments

# Bill Blogs in C# said on 19 August, 2009 08:29 AM

Chris Marinos started Elevate as a learning time project at SRT Solutions.  It’s still very young

# Dave Redding said on 19 August, 2009 10:08 AM

Hey Chris;

This looks like an awesome utility.  I look forward to grabbing it off codeplex and seeing what I can do with it.

Thanks!

Dave.

# cmarinos said on 19 August, 2009 02:49 PM

Thanks Dave. I hope you find it useful. Let us know if you have any suggestions.

-Chris

# James Miles said on 09 September, 2009 10:23 PM

Hi Chris,

It's about time the community started putting something like this together! Well done :)

Could you explain some things for me?

RE: public void SelectWithIndex()

How does this differ from the Select overload that is alreaady provided in LINQ?

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)

"Projects each element of a sequence into a new form by incorporating the element's index."

RE: public void Select2()

There was an operator like this published on MSDN. They called it "Combine".

msdn.microsoft.com/.../aa336749.aspx

RE: Option Types

Is there anyway Nullable types could be used instead? Seems similar to me?

Keep up the good work,

James

# Joe Wasson said on 10 September, 2009 01:26 AM

There's some helpful stuff in there indeed.  I have some feedback, as well as some patches (see website link above).

In your TryParse extensions, I'd like to see "null" treated as "fail to parse" and not an exception.  I've always found it annoying that I have to separately check for null (and then have FxCop complain about not using IsNullOrEmpty) when the Tryparse method can just as easily say "Hey, I can't parse this; return null;"

In a similar vein, I've always preferred treating null strings as empty strings (except when it represents "no value" versus "empty value").  Likewise, I prefer treating null collections as empty collections (hence the "EmptyIfNull()" extension in the patches above).

The patches I've provided add some functionality, and fix a couple of issues.  Some of my favorites are .Intercept(), .Act(), .Once(), and .ValueOrDefault().  I kind of like the Option class, especially how it disambiguates "null as a value" (major difference from Nullable<>).  I've added some routines around that.  In other places, I just removed redundant code and instead called code that was already there.

Cheers,

Joe

# eti said on 10 September, 2009 01:55 AM

Hi,

It's a nice idea you have there, but coming myself from a strong c++ background i would recommend that you don't yet compare it to boost. Everything in boost is about high quality. I'm not saying that your lib is not of quality, just that maybe you should wait for more peer reviews and general adoption before comparing with something as boost. One step forward would be to start defining the complexity requirements for your functions ( ex. the sequences compare is done in O(n) ).

Anyway I think overall is a good idea to get something like this going. Good luck.

# Rabeeh Abla said on 10 September, 2009 08:20 AM

Hi, good work,

Needs more documentation and examples, there is lots of complexity in the design. Could have been simpler..

Regards

# Drew Noakes said on 10 September, 2009 08:53 AM

The functionality provided by Through is already available in the BCL, though with a less readable syntax:

var nums = Enumerable.Range(1, 10);

Option feels a lot like nullable types, though with Option you could express a non-none value of null which could concievably be useful but I can't imagine a case offhand.

Like the Match stuff.

Thanks for sharing.

# Pop Catalin said on 10 September, 2009 08:54 AM

Select2 should be renamed to Zip :), that's how it's usually called.

# cmarinos said on 10 September, 2009 10:18 AM

@James Miles

Thanks for the positive feedback!

RE: SelectWithIndex()

You're right here, there doesn't seem to be any difference. I think we got a little carried away when writing ForEachWithIndex.

RE: Option Types

Nullable types are similar to Option types. I find that Option types are easier to deal with, though. I'll try to get a post out going in to more detail. here.

RE: Select2

See my rant on this below.

-Chris

# cmarinos said on 10 September, 2009 10:22 AM

@Joe Wasson

Thanks for the patches and feedback.

You have some good points on TryParse with regards to exceptions and emptiness.

I'm looking forward to checking the patches out, and seeing what other contributions you make in the future!

-Chris

# cmarinos said on 10 September, 2009 10:28 AM

@eti

You're right. I draw the comparison to Boost as a way to answer the question "what does the library do?". I don't mean to imply that the library is nearly as mature or rigorously tested as boost is.

Hopefully, we'll get there someday, though!

-Chris

# cmarinos said on 10 September, 2009 10:32 AM

@Rabeeh Abla

For our documentation and examples, we've been using the Elevate.Guide test project.

That being said, where would you like to see more documentation, what types of documentation would you prefer, and what areas do you find to be too complex?

Thanks for stopping by!

-Chris

# cmarinos said on 10 September, 2009 10:40 AM

@Drew Noakes

Enumerable.Range does the basics of Through, but we have a couple other features. First, you can't specify an offset with Enumerable.Range, so doing something like 1.Through(10, 2) isn't provided. Also, we .Through lets you enumerate in reverse to. For example, 10.Through(0).

I'll try to post about option types vs nullables.

Thanks for the feedback!

-Chris

# cmarinos said on 10 September, 2009 10:55 AM

@Pop Catalin, @James Miles

.Zip() (sadly) appears to be the name that the BCL team wants to use for .Select2() in .NET 4.0:

msdn.microsoft.com/.../dd267698%28VS.100%29.aspx

Unfortunately, the .Zip() function in every other language that I checked uses the behavior that we have in Elevate.

Python: docs.python.org/.../functions.html

F#: research.microsoft.com/.../Microsoft.FSharp.Collections.Seq.html

Haskell: www.zvon.org/.../zip_f.html

Sadly, if .NET 4.0 were to release today, there would be a System.Linq version of .Zip() that did one thing while the F# standard library would include it's own "Seq.zip" function with totally different behavior.

The best thing might be to do what Ruby does, which is to call both of them .Zip() and use overloads to disambiguate.

Ruby: www.ruby-doc.org/.../Array.html

</rant>

-Chris

# //TODO - Chris Marinos' Blog said on 10 September, 2009 06:02 PM

Some of the feedback that we’ve received about Elevate has to do with Option types and how they are different

# Pete said on 11 September, 2009 05:18 AM

Hi,

Elevate look s great, but..

unfortunatly I still have to work on some dotnet 2.0 projects, so it would be fine to have a 2.0 version of Elevate.

ciao

Pete

# Joe said on 11 September, 2009 05:31 AM

Hi,

I've just come across this today and it looks good. One Comment and one feature I would like to add are.

Comment

The could easily be a dumping ground of useful snippets and features and in trying to be all things to all people, it becomes bloated and cumbersum. Something to be aware as this grows.

Feature

Adding smoke to the fire, one feature I would like to see is the IsNumeric.

support.microsoft.com/.../329488

Thanks,

Joe

# Alec Zorab said on 11 September, 2009 11:11 AM

Hey guys, I enjoyed reading through your code, and just wanted to point you guys int he direction of NVentive's Umbrella, a similar project also hosted on CodePlex. There's some great ideas in both libraries - perhaps it would be worth taking a look to reduce the amount of duplicated effort?

Thanks

Alec

# cmarinos said on 12 September, 2009 01:14 AM

@Pete-

Supporting a 2.0 version of Elevate would be nice, but at this point in time, it isn't on our //TODO list. There are a few variables to consider, and a lot of the functionality becomes less useful without extension methods.

I think that we will probably spend more of our time working on a 4.0 version of Elevate, but this is all subject to change if someone has the time/desire to work on it (hint hint)!

-Chris

# cmarinos said on 12 September, 2009 01:21 AM

@Joe-

You've definitely nailed one of our biggest concerns with building a library like this. So far, with the exception of a couple of the crazier functional constructs that we adapted from Matthew Podwysocki's Functional C# Samples, we've only added utilities that we have already come across a need for in our applications. In the short term, I think that this has helped the project to stay grounded.

As the project grows, however, I think the answer is to reach out to the community to see what features should be added and which are better off left out or made into separate libraries.

As for the IsNumeric, we'll try to take a look at that and see if it makes sense in a future release.

Thanks Joe!

-Chris

# cmarinos said on 12 September, 2009 01:37 AM

@Alec Zorab-

Thanks for the feedback!

Before building Elevate, we looked at a few code bases that were trying to fill a similar need, including Umbrella. Personally, I do not feel like any of them hit the sweet spot that we are going for with Elevate, but I'm obviously biased :)

There are definitely some cool things in Umbrella that we wouldn't mind having in Elevate, but unfortunately, it looks like development on that project has slowed significantly (the last commit was in early March). Rather than trying to patch Umbrella with all of the functionality that we wanted, we decided to go a different route.

With Elevate, we hope to maintain a higher level of quality and control bloat better than we could by patching any existing project. Hopefully this ends up being the right approach!

-Chris

# Onur Gumus said on 12 September, 2009 04:58 AM

You may want to look into nemerle. It also has all of these features in the language

# cmarinos said on 12 September, 2009 10:50 AM

@Onur Gumus-

I had never heard of Nemerle before, but after a quick glance, it definitely looks beyond the scope of what we're trying to accomplish with Elevate. Our goal is to extend the BCL, not to modify the C# language.

That being said, does Nemerle's standard library really provide all of the functions that Elevate has for working with sequences? I wasn't able to find that.

Also, as far as functional/imperative/OOP hybrids go, why would someone choose Nemerle over F# on .NET? I realize there are significant syntax differences, but in my opinion, that is a good thing for F#, not a bad thing.

Anyway, thanks a lot for the feedback! Hopefully I'll learn more about Nemerle in the future.

-Chris

# Anthony Gatlin said on 13 September, 2009 02:34 AM

@cmarinos

I understand Pete's desire for .NET 2.0 support, but I encourage you NOT to implement it. Trying to be backwards compatible simply results in bloated code and makes the library more difficult to maintain. There are very few, if any, good reasons not to upgrade to .NET 3.51 sp1 since it is fully compatible with all existing .NET 2.0 apps.

Also, do you have a plan to allow the community to participate in Elevate's development? If so, do you have any sort of a roadmap for planned features or perhaps a list of suggestions for items you would like to implement?

If you plan to allow the community to contribute (and I hope you do), it might be worth posting a list of potential features, getting some feedback, and then letting some of the folks out here contribute.

This is a project that could really take off, and judging from the comments you already have, I don't think you'll have any difficulty getting people involved.

# Pittsburgh said on 14 September, 2009 12:18 AM

Are there currently any plans to dig into graph algorithms? That, I think, is the coolest part of Boost and the most missed in .NET.

# Pete said on 14 September, 2009 06:14 AM

@Chris,

I just added LinqBridge (www.albahari.com/.../linqbridge.aspx) to the Elevate and Elevate.Guide projects and nearly everything compiles and runs fine. Only in BufferedStream.cs a problem exists with the Mock class.  

-Peter

# Vandana said on 14 September, 2009 06:35 AM

Nice utility!

# Justin Bailey said on 14 September, 2009 01:50 PM

Great idea! I haven't dug into the code yet so I hope my request isn't too redundant:

 * Proper support for folds over sequences, and support for folds over non-empty sequences. In C# 2, they had ConvertAll on Array, which was sort of a fold. LINQ has some other name for it but its awkward.

Have you looked at the Haskell standard "Prelude" for inspiration? It's a great example of a mature, thoroughly argued, toolbox for functional programming.

# cmarinos said on 14 September, 2009 08:36 PM

@Anthony Gatlin-

I agree that there are few reasons not to upgrade to 3.5, but it isn't always the developer's choice when working with a large company. As @Peter pointed out, it looks like LinqBridge may be a good way to support 2.0, though.

As for community involvement, this is something that is very important to us. We want Elevate to be a project that people want to both use and contribute to. Hopefully we'll have more on community involvement later this week.

Thanks for the feedback!

-Chris

# cmarinos said on 14 September, 2009 08:39 PM

@Pittsburgh-

We don't currently have any plans for graph algorithms in Elevate, but that is certainly something that we can look into if the demand is there.

Thanks for the suggestion (as long as you aren't a Penguins fan).

-Chris

# cmarinos said on 14 September, 2009 08:48 PM

@Pete-

I hadn't heard of LinqBridge before, that's pretty cool.

I suspect that the problem you're having with LinqBridge and the Elevate.Guide project is due to our use of Moq (http://code.google.com/p/moq/). As far as I know, Moq doesn't support 2.0, although you may be able to use LinqBridge to build a 2.0 compatible version.

Either way, assuming the main project compiles with LinqBridge, you should be able to use it without problem.

We can take a look at supporting 2.0 through LinqBridge in the future and adding it to our CI builds.

Thanks again, Pete!

-Chris

# cmarinos said on 14 September, 2009 08:49 PM

@Vandana-

Thanks for the positive feedback!

-Chris

# cmarinos said on 14 September, 2009 08:49 PM

@Vandana-

Thanks for the positive feedback!

-Chris

# cmarinos said on 14 September, 2009 09:16 PM

@Justin Bailey-

I think Linq calls it "Aggregate". We can take a look at supporting folds better than the BCL does, but some functional approaches can be difficult to implement in C# due to the lack of tail call optimization.

As for Prelude, you're right about it being a good library to draw inspiration from. We looked there a few times during the initial development of Elevate, but I (shamefully) admit that my Haskell foo is weaker than I'd like. Because of that, I haven't been able to draw from Prelude as much as other sources. As you'll see when you look through the source, we do draw a lot from the F# standard library, though.

Finally, it's worth noting that not everything translates as well as you'd like from a functional language into C#. Functions that are very elegant in functional languages can turn into ugly, difficult to use monstrosities in C#. Often, there are more idiomatic (for C#) ways to perform these operations that also perform better. With Elevate, we'd like to implement the ones that make sense, but not force a functional approach where it just doesn't work in C#. Take a look at our Unfold implementation for an example of the elegant to ugly conversion.

Thanks for the good thoughts!

-Chris

# aman tur said on 16 September, 2009 01:38 AM

Well done Chris, keep the good work up!

# Pete said on 16 September, 2009 04:29 AM

@Chris,

yes indeed moq is the problem, but of course it is no show stopper. So there is no need for me, to dig into moq to build a 2.0 compatible version.

Thanks for considering to support 2.0 through LinqBridge in the future.

Keep up the good work,

-Pete

# Dan Fitch said on 16 September, 2009 05:07 PM

Looks interesting.

Pittsburgh, re: graphs, you should probably check out QuickGraph

# Wil Bloodworth said on 19 September, 2009 01:21 PM

Great job Chris!  Stay motivated and don't let any negativity affect your goal... it's a great goal.

- Wil

# Steve Solomon said on 21 September, 2009 04:35 AM

Being a fan of F# and functional programming, having had a quick look at the library I like the look of it.  One question regarding the Tuple type.  Is this a hand rolled implementation?  The BCL is introducing a Tuple type in .net 4.0.  How will this impact on you library.  Do you plan to migrate to using the BCL version when available?

# Steve Solomon said on 21 September, 2009 04:41 AM

Forget my earlier comment.  Just had a proper look at the code, and it answers my question.

# cmarinos said on 21 September, 2009 04:22 PM

@Steve Solomon-

Glad to hear you like look of Elevate so far.

As you've seen with the Tuple type, we're using a hand rolled class until we release a 4.0 compatible version of Elevate. We'll hopefully be addressing our 4.0 strategy in the next few days.

-Chris

# cmarinos said on 21 September, 2009 04:23 PM

@aman tur, @Dan Fitch, @Wil Bloodworth-

Thanks for the positive feedback!

-Chris

# Vladekk said on 25 September, 2009 10:38 AM

Very good thing I'd add instantly is Descendants extension method for traversing any tree and selecting its children.

Something like this:

mutable.net/.../using-linq-to-objects-for-recursion.aspx

# Mohit Dwivedi said on 29 September, 2009 02:56 AM

Its good approach for young .net developer . I am adding some of my uitlities

# Travis Parks said on 02 October, 2009 12:23 PM

I like some of your methods and classes. I'm not too sure about your naming standards.

I have a library called LimitedInterfaces. Feel free to borrow some of my implementations and unit tests. My library is .NET 2.0 compatible, so you won't see any Extension Methods. Just slap in a "this" here and there and you'll be good to go!

If you guys would like someone with a little knowledge about writing an algorithm-like library, feel free to look me up. It would be really cool to work on a project with some other folks.

# Brian said on 08 October, 2009 02:48 PM

In my opinion, 1.Through(10) goes too far in the use of extension methods.  Using literals in this way seems wrong.

Also, in practice one doesn't really build up sequences of constants.

Maybe it would be better to generalize by a sequence builder of arbitrary types off of an integer iterator.  For example: the integers 0..9 maps to the sequence 10..100 this way:

int length = 10;

var seq = BuildSeq(length, n => (n + 1) * 10 );

# cmarinos said on 08 October, 2009 11:33 PM

@Brian-

It's cool if you aren't down with the .Through style off int. It seems to work well in languages like Ruby, though.

Also note that you aren't required to use it off constants. In practice, you'd more likely see something like this:

    var nums = start.Through(end);

You can also use the static method syntax:

    var nums = ThroughExtensions.Through(start, end);

We might want to change the name on the "ThroughExtensions", part though. ...If only C# supported modules like F#...

 

 

To accomplish the 0..9 to 10..100 mapping, see TImes:

    9.Times(n => (n+1) *10);

or

    Seq.Times(10, n=> (n+1) * 10);

if you don't like extending off int.

 

 

Thoughts? (this might also be a good topic to discuss over on our Google group.)

-Chris

# cmarinos said on 08 October, 2009 11:35 PM

@Mohit Dwivedi

Thanks, but we hope that Elevate is a good approach for developers of all ages :)

-Chris

# cmarinos said on 08 October, 2009 11:36 PM

@Vladekk-

Thanks, we should probably look into adding support for traversals of collections like that.

-Chris

# Niki said on 13 October, 2009 03:21 AM

Just curious: Why would you use SelectIndex instead of the Enumerable.Select overload that passes an index to the select-function?

-> msdn.microsoft.com/.../bb534869.aspx

# cmarinos said on 13 October, 2009 05:17 PM

@Niki-

You wouldn't. It turns out that we got a little carried away when building LINQ extensions and forgot about the standard LINQ version. We've corrected the issue in a recent checkin by Obsoleted the SelectWithIndex() method.

Good catch, and thanks for the feedback!

-Chris

# alimbada said on 15 October, 2009 09:27 AM

I think everyone would be better off if you contributed to Mono.Rocks (www.mono-project.com/Rocks) rather than duplicating effort in this manner.

# Doug.UK said on 16 October, 2009 05:02 AM

I agree about the " duplicating effort" risk as all that will give us is the VHS/Betamax war later. Cool that you are bothered to explore, research this. With luch the best of both will get consolidated into something better.

I would like to point out that zinngyRed on gray is not that visible, eg look at "# Niki said on 13 October, 2009 03:21 AM " post.

# GioL said on 09 November, 2009 05:23 AM

awesome tool.  This could save time in first stage of development.  Thanks

# Amit said on 25 November, 2009 02:06 PM

Excellant work..Thanks for sharing

# Matthias Broschk said on 01 December, 2009 07:32 PM

Thank you, great works, with these continuous developments I am really curious abous how a 'common' C# code piece will look like in 5-10 years.

Leave a Comment

(required) 
(required) 
(optional)
(required)