tags:

views:

55

answers:

2

what is wrong in the below

Enumerable.Range(0, objEntityCode.Count - 1).Select(i => 
{ 
options.Attributes[i] = new EntityCodeKey 
{ 
EntityCode = objEntityCode[i].EntityCodes 
, OrganizationCode = Constants.ORGANIZATION_CODE }; 
})
.ToArray(); 

Throwing error The type arguments for method 'System.Linq.Enumerable.Select(System.Collections.Generic.IEnumerable, System.Func)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

But this works

Enumerable.Range(0, objEntityCode.Count - 1).ToList().ForEach(i =>  
                { 
                    options.Attributes[i] = new EntityCodeKey 
                    { 
                         EntityCode = objEntityCode[i].EntityCodes 
                         , OrganizationCode = Constants.ORGANIZATION_CODE   
                    };  

                } 
             ); 

Using C#3.0.

Purpose: I am learning LINQ / LAMBDA and trying to do the same program in different way.

Thanks.

+2  A: 

As I stated in a comment - your lambda expression doesn't return anything. Therefore it can't be used in a projection. Select is meant to transform a sequence of items of one type into a sequence of items of another type. You're not doing any transforming in your lambda expression - you've just got an assignment.

Now you could do this:

Enumerable.Range(0, objEntityCode.Count - 1).Select(i => 
{ 
    return options.Attributes[i] = new EntityCodeKey 
    { 
        EntityCode = objEntityCode[i].EntityCodes,
        OrganizationCode = Constants.ORGANIZATION_CODE
    }; 
})
.ToArray();

I wouldn't recommend it though. I appreciate you're currently learning about LINQ and lambda expressions, but it's worth learning when not to use them too - and this looks like a situation where you really, really shouldn't use them.

Jon Skeet
As a purely intellectual exercise, it actually *would* return something if the semicolon were omitted from within the statement (since it would then be a single-line lambda, which doesn't require the `return` statement).
Adam Robinson
@Adam. You would also need to remove the braces around the lambda as a statement in braces with no semicolon will not compile.
Igor Zevaka
As in `i=>{i+5}` won't compile, but `i=>i+5` will.
Igor Zevaka
+1  A: 

Look at what you have inside the Select and ForEach method calls:

options.Attributes[i] = new EntityCodeKey 
    { 
        EntityCode = objEntityCode[i].EntityCodes 
        , OrganizationCode = Constants.ORGANIZATION_CODE   
    };

This is essentially an Action<int> -- that is, code that does something but doesn't return something. This is why it makes sense within ForEach but not Select -- Select expects (in this case) a Func<int, T> -- code that returns something (of some type T). Since you are simply assigning Attributes[i] to a new EntityCodeKey, this code does not fall under the umbrella of what you would normally find within a Select call.

Note that technically, the above code actually would return something -- namely, the value stored in options.Attributes[i] -- if you removed the semicolon from the end. Why? Two reasons:

  1. A single-line lambda expression (not terminating in a semi-colon) returns whatever it evaluates to. This is why something like person => person.Name can actually be interpreted as a Func<Person, string>.
  2. An assignment operation evaluates to the assigned value. This is why you can write x = y = z -- because y = z actually evalutes to the newly assigned value of y.

So it's true: your code, sans semi-colon, would actually evaluate to options.Attributes[i]. But writing the code in this way would be, in my opinion anyway, pretty confusing.

Dan Tao