W rzeczywistości możliwe jest zwrócenie anonimowego typu z metody w określonym przypadku użycia. Spójrzmy!
W języku C # 7 możliwe jest zwrócenie anonimowych typów z metody, chociaż wiąże się to z niewielkimi ograniczeniami. Zamierzamy użyć nowej funkcji języka zwanej funkcją lokalną wraz ze sztuczką pośredniczącą (kolejna warstwa pośrednictwa może rozwiązać każde wyzwanie programistyczne, prawda?).
Oto przypadek użycia, który niedawno zidentyfikowałem. Chcę rejestrować wszystkie wartości konfiguracyjne po ich załadowaniu zAppSettings
. Czemu? Ponieważ istnieje pewna logika dotycząca brakujących wartości, które powracają do wartości domyślnych, trochę analizy i tak dalej. Łatwym sposobem rejestrowania wartości po zastosowaniu logiki jest umieszczenie ich wszystkich w klasie i serializowanie ich do pliku dziennika (przy użyciu log4net). Chcę też ująć złożoną logikę postępowania z ustawieniami i oddzielić to od tego, co muszę z nimi zrobić. Wszystko to bez tworzenia nazwanej klasy, która istnieje tylko do jednorazowego użytku!
Zobaczmy, jak rozwiązać ten problem, używając funkcji lokalnej, która tworzy typ anonimowy.
public static HttpClient CreateHttpClient()
{
// I deal with configuration values in this slightly convoluted way.
// The benefit is encapsulation of logic and we do not need to
// create a class, as we can use an anonymous class.
// The result resembles an expression statement that
// returns a value (similar to expressions in F#)
var config = Invoke(() =>
{
// slightly complex logic with default value
// in case of missing configuration value
// (this is what I want to encapsulate)
int? acquireTokenTimeoutSeconds = null;
if (int.TryParse(ConfigurationManager.AppSettings["AcquireTokenTimeoutSeconds"], out int i))
{
acquireTokenTimeoutSeconds = i;
}
// more complex logic surrounding configuration values ...
// construct the aggregate configuration class as an anonymous type!
var c = new
{
AcquireTokenTimeoutSeconds =
acquireTokenTimeoutSeconds ?? DefaultAcquireTokenTimeoutSeconds,
// ... more properties
};
// log the whole object for monitoring purposes
// (this is also a reason I want encapsulation)
Log.InfoFormat("Config={0}", c);
return c;
});
// use this configuration in any way necessary...
// the rest of the method concerns only the factory,
// i.e. creating the HttpClient with whatever configuration
// in my case this:
return new HttpClient(...);
// local function that enables the above expression
T Invoke<T>(Func<T> func) => func.Invoke();
}
Udało mi się skonstruować anonimową klasę, a także zawrzeć logikę radzenia sobie ze złożonym zarządzaniem ustawieniami, wszystko wewnątrz CreateHttpClient
i wewnątrz jego własnego „wyrażenia”. To może nie być dokładnie to, czego chciał OP, ale jest to lekkie podejście z typami anonimowymi, które jest obecnie możliwe w nowoczesnym C #.