Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assign a function delegate that returns an anonymous type to a variable

The code below is valid:

IEnumerable<SomeThing> things = ...;

// map type SomeThing to a new anonymous type, resulting in a strongly typed 
// sequence based on an anon type

var newList = things.Select(item =>
    {
        return new
        {
            ID = item.ID,
            DateUpdatedOrCreated = ((DateTime)(item.DateUpdated ??
                     item.DateCreated)).ToShortDateString(),
            Total = item.Part1 + item.Part2
        };
    });

newList now appears in Visual Studio as IEnumerable<'a> and is strongly typed with the anonymous type created in the function. That is so cool.

What I can't seem to do is figure out a way to assign just the lambda expression (and not the enumeration) to an implicitly typed variable. Even though the compiler has no problem with the anonymous type in the context above, if I try (say)

var func = (SomeThing item)=> {
        return new { ... };
    };

I get the error "Cannot assign lambda expression to implicitly-typed local variable". This seems a strange compiler limitation; unless I am missing something, the types are just as non-ambiguous in the 2nd example as they are in the first first: both type parameters are well defined.

Is there any way to do this? Since it's an anonymous type, of course, I don't have any way to use a type to assign it explicitly, so it seems I'd be stuck with making a class for the output type if not.

Update

Shortly after going about my merry way with Jon Skeet's answer, I found a similar dilemma instantiating classes. In case it's not obvious, the same trick can be used to create strongly typed classes using inferred anonymous types.

class Processor<T,U>
{
    public Processor(Func<T,U> func) {

    }
}

// func is a delegate with anon return type created using method in answer below

var instance = new Processor(func);   // does not compile! Requires type arguments!

cannot be created directly, but can be created in much the same way as the trick below:

public static Processor<T,U> Create<T,U>(Func<T,U> func) {
    return new Processor<T,U>(func);
}

var instance = Processor.Create(func);   // all good
like image 343
Jamie Treworgy Avatar asked May 09 '12 20:05

Jamie Treworgy


1 Answers

You can do it via type inference:

var func = BuildFunc((SomeThing item) => {
    return new { ... };
});

...

static Func<TSource, TResult> BuildFunc<TSource, TResult>(
    Func<TSource, TResult> function) {
    return function;
}

Note that BuildFunc doesn't really do anything - it just provides the method call needed to get the compiler to do type inference for the generic type arguments for Func<,> - it adds the information that you're interested in Func<,>, basically - that's information which can't be specified as part of a variable declaration, without also specifying the type arguments.

like image 147
Jon Skeet Avatar answered Sep 19 '22 01:09

Jon Skeet