2012-05-09 47 views
6

Poniższy kod jest ważny:Przypisywanie delegata funkcję zwracającą typ anonimowy do zmiennej

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 teraz pojawia się w Visual Studio jako IEnumerable<'a> i jest silnie wpisany z anonimowego typu utworzonego w funkcji. To jest takie super.

To, czego nie mogę zrobić, to znaleźć sposób na przypisanie tylko wyrażenia lambda (a nie wyliczenia) do niejawnie wpisanej zmiennej. Mimo, że kompilator nie ma problemu z anonimowych typu w kontekście powyższego, jeśli próbuję (powiedzmy)

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

pojawia się błąd „Nie można przypisać wyrażenie lambda do niejawnie wpisany zmiennej lokalnej”. Wydaje się to dziwnym ograniczeniem dla kompilatora; chyba że czegoś brakuje, typy są tak samo niejednoznaczne w drugim przykładzie, ponieważ są w pierwszym pierwszym: oba parametry typu są dobrze zdefiniowane.

Czy jest jakiś sposób to zrobić? Ponieważ jest to anonimowy typ, oczywiście, nie mam żadnego sposobu na użycie typu, aby przypisać go jawnie, więc wydaje mi się, że utknąłem z tworzeniem klasy dla typu wyjściowego, jeśli nie.

Aktualizacja

Krótko po przejściu na temat mojego wesołego sposób z odpowiedzi Jon Skeet jest, znalazłem podobny dylemat każdy węzeł klas. W przypadku, gdy nie jest to oczywiste, ten sam trik może być użyty do stworzenia silnie typowanych klas z wykorzystaniem wnioskowych typów anonimowych.

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! 

nie mogą być tworzone bezpośrednio, ale mogą być tworzone w taki sam sposób, jak na poniższym trick:

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 

Odpowiedz

8

można to zrobić poprzez wnioskowanie typu:

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

... 

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

Należy pamiętać, że BuildFunc tak naprawdę nic nie robi - po prostu zapewnia wywołanie metody potrzebne, aby kompilator robił wnioskowanie typu dla ogólnych argumentów typu dla Func<,> - dodaje informacje Interesuje Cię w szczególności: Func<,>, czyli informacje, których nie można określić jako część deklaracji zmiennych, bez określania argumentów typu.

+0

Działa to, ponieważ wnioskowanie o typie jest inteligentniejsze niż wnioskowanie typu dla 'var'. (Zakładam, że jon może być w stanie wyjaśnić, dlaczego nawet nie mogę.) – Servy

+0

Dobra odpowiedź. Dodatkowe informacje: Działa to, ponieważ nie musisz tutaj określać typu zmiennej. Kompilator nie może po prostu wnioskować o typie zmiennej, ponieważ istnieje wiele typów delegatów, z których mógłby wybierać. – usr

+0

@Servy: To nie jest kwestia bycia mądrzejszym jako takim - jest to kwestia możliwości określenia, że ​​chcesz delegata 'Func', ale określenie tego ogólnie. –

Powiązane problemy