remarks generate example c# function parameters anonymous-types

c# - generate - ¿Cómo pasar tipos anónimos como parámetros?



params comments c# (10)

¿Cómo puedo pasar tipos anónimos como parámetros a otras funciones? Considera este ejemplo:

var query = from employee in employees select new { Name = employee.Name, Id = employee.Id }; LogEmployees(query);

query variable aquí no tiene tipo fuerte. ¿Cómo debería definir mi función LogEmployees para aceptarla?

public void LogEmployees (? list) { foreach (? item in list) { } }

En otras palabras, ¿qué debería usar en lugar de ? marcas.


"dinámico" también se puede usar para este propósito.

var anonymousType = new { Id = 1, Name = "A" }; var anonymousTypes = new[] { new { Id = 1, Name = "A" }, new { Id = 2, Name = "B" }; private void DisplayAnonymousType(dynamic anonymousType) { } private void DisplayAnonymousTypes(IEnumerable<dynamic> anonymousTypes) { foreach (var info in anonymousTypes) { } }


Creo que deberías hacer una clase para este tipo anónimo. Eso sería lo más sensato para hacer en mi opinión. Pero si realmente no quieres, podrías usar dinámicas:

public void LogEmployees (IEnumerable<dynamic> list) { foreach (dynamic item in list) { string name = item.Name; int id = item.Id; } }

Tenga en cuenta que esto no está fuertemente tipado, por lo que si, por ejemplo, Name cambia a EmployeeName, no sabrá que hay un problema hasta el tiempo de ejecución.


En lugar de pasar un tipo anónimo, pase una Lista de un tipo dinámico:

  1. var dynamicResult = anonymousQueryResult.ToList<dynamic>();
  2. Firma del método: DoSomething(List<dynamic> _dynamicResult)
  3. Método de llamada: DoSomething(dynamicResult);
  4. hecho.

¡Gracias a Petar Ivanov !


Lamentablemente, lo que intentas hacer es imposible. Bajo el capó, la variable de consulta se escribe para ser un IEnumerable de un tipo anónimo. Los nombres de tipos anónimos no se pueden representar en el código de usuario, por lo tanto, no hay forma de convertirlos en un parámetro de entrada para una función.

Su mejor opción es crear un tipo y usarlo como el retorno de la consulta y luego pasarlo a la función. Por ejemplo,

struct Data { public string ColumnName; } var query = (from name in some.Table select new Data { ColumnName = name }); MethodOp(query); ... MethodOp(IEnumerable<Data> enumerable);

Sin embargo, en este caso, solo está seleccionando un solo campo, por lo que puede ser más fácil simplemente seleccionar el campo directamente. Esto hará que la consulta se tipee como un IEnumerable del tipo de campo. En este caso, nombre de columna.

var query = (from name in some.Table select name); // IEnumerable<string>


No puede pasar un tipo anónimo a una función no genérica, a menos que el tipo de parámetro sea object .

public void LogEmployees (object obj) { var list = obj as IEnumerable(); if (list == null) return; foreach (var item in list) { } }

Los tipos anónimos están destinados al uso a corto plazo dentro de un método.

Desde MSDN - Tipos anónimos :

No puede declarar un campo, una propiedad, un evento o el tipo de devolución de un método como de tipo anónimo. Del mismo modo, no puede declarar que un parámetro formal de un método, propiedad, constructor o indizador tiene un tipo anónimo. Para pasar un tipo anónimo, o una colección que contiene tipos anónimos, como un argumento para un método, puede declarar el parámetro como tipo de objeto . Sin embargo, al hacerlo, se frustra el propósito de una tipificación fuerte.

(énfasis mío)

Actualizar

Puede usar genéricos para lograr lo que quiere:

public void LogEmployees<T>(IEnumerable<T> list) { foreach (T item in list) { } }


Normalmente, haces esto con genéricos, por ejemplo:

MapEntToObj<T>(IQueryable<T> query) {...}

El compilador debe inferir la T cuando llama a MapEntToObj(query) . No estoy muy seguro de lo que quiere hacer dentro del método, así que no puedo decir si esto es útil ... el problema es que dentro de MapEntToObj todavía no puede nombrar la T , puede:

  • llamar a otros métodos genéricos con T
  • usa la reflexión en T para hacer cosas

pero aparte de eso, es bastante difícil manipular tipos anónimos, sobre todo porque son inmutables;

Otro truco (al extraer datos) es pasar un selector, es decir, algo así como:

Foo<TSource, TValue>(IEnumerable<TSource> source, Func<TSource,string> name) { foreach(TSource item in source) Console.WriteLine(name(item)); } ... Foo(query, x=>x.Title);


Puede usar genéricos con el siguiente truco (conversión al tipo anónimo):

public void LogEmployees<T>(IEnumerable<T> list) { foreach (T item in list) { var typedItem = Cast(item, new { Name = "", Id = 0 }); // now you can use typedItem.Name, etc. } } static T Cast<T>(object obj, T type) { return (T)obj; }


Puedes hacerlo así:

public void LogEmployees<T>(List<T> list) // Or IEnumerable<T> list { foreach (T item in list) { } }

... pero no podrás hacer mucho con cada elemento. Puede llamar a ToString, pero no podrá usar (digamos) Name and Id directamente.


Si sabe que sus resultados implementan una cierta interfaz, puede usar la interfaz como tipo de datos:

public void LogEmployees<T>(IEnumerable<T> list) { foreach (T item in list) { } }


Yo usaría IEnumerable<object> como tipo para el argumento. Sin embargo, no es una gran ganancia para el elenco explícito inevitable. Aclamaciones