una - metodos de listas en c#
¿Puedo crear un diccionario de tipos genéricos? (8)
¿Qué tal Diccionario suponiendo que estás en C # 4
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Fuente: https://stackoverflow.com/a/5038029/3270733
Me gustaría crear un objeto de diccionario, con claves de cadena, que contengan valores que sean de tipo genérico. Imagino que se vería algo como esto:
Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();
Y me permite agregar lo siguiente:
d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());
Sé que puedo hacerlo para una lista de cadenas, por ejemplo, usando esta sintaxis:
Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());
pero me gustaría hacerlo para una lista genérica si es posible ...
2 preguntas entonces:
- ¿Es posible?
- ¿Cuál es la sintaxis?
Muchas gracias,
Jon
Algo como esto funcionaría?
public class GenericDictionary
{
private Dictionary<string, object> _dict = new Dictionary<string, object>();
public void Add<T>(string key, T value) where T : class
{
_dict.Add(key, value);
}
public T GetValue<T>(string key) where T : class
{
return _dict[key] as T;
}
}
Básicamente, envuelve todo el casting detrás de escena para ti.
EDITAR: Ahora he vuelto a leer la pregunta ...
No puede hacer esto, pero una colección personalizada lo manejaría en cierta medida. Básicamente tendrías un método Add
genérico:
public void Add<T>(string key, List<T> list)
(La colección en sí no sería genérica, a menos que quisiera que el tipo de clave sea genérico).
Sin embargo, no se pudieron extraer valores de manera fuertemente tipada porque el compilador no sabrá qué tipo ha usado para una clave en particular. Si convierte la clave en el tipo en sí, termina con una situación ligeramente mejor, pero que todavía no es compatible con las colecciones existentes. Esa es la situación a la que respondía mi respuesta original.
EDIT: respuesta original, cuando no había leído la pregunta correctamente, pero que puede ser informativa de todos modos ...
No, no se puede hacer que un tipo de argumento dependa de otro, me temo. Es solo una de las cosas que uno podría querer expresar en un sistema de tipo genérico pero que las limitaciones de .NET no permiten. Siempre habrá tales problemas, y los diseñadores de .NET optaron por mantener los genéricos relativamente simples.
Sin embargo, puede escribir una colección para aplicarla con bastante facilidad. Tengo un ejemplo en una publicación de blog que solo conserva un único valor, pero sería fácil ampliarlo para usar una lista.
Estamos utilizando muchos reflejos para crear una herramienta de administración extensible. Necesitábamos una forma de registrar elementos en la búsqueda global en la definición del módulo. Cada búsqueda arrojaría resultados de manera consistente, pero cada uno tenía dependencias diferentes. Aquí hay un ejemplo de nosotros registrando la búsqueda de un solo módulo:
public void ConfigureSearch(ISearchConfiguration config)
{
config.AddGlobalSearchCallback<IEmploymentDataContext>((query, ctx) =>
{
return ctx.Positions.Where(p => p.Name.Contains(query)).ToList().Select(p =>
new SearchResult("Positions", p.Name, p.ThumbnailUrl,
new UrlContext("edit", "position", new RouteValueDictionary(new { Id = p.Id }))
));
});
}
En el fondo durante el registro del módulo, iteramos sobre cada módulo y agregamos el Func a una tabla de búsqueda con una instancia de:
public class GenericFuncCollection : IEnumerable<Tuple<Type, Type, Object>>
{
private List<Tuple<Type, Type, Object>> objects = new List<Tuple<Type, Type, Object>>();
/// <summary>
/// Stores a list of Func of T where T is unknown at compile time.
/// </summary>
/// <typeparam name="T1">Type of T</typeparam>
/// <typeparam name="T2">Type of the Func</typeparam>
/// <param name="func">Instance of the Func</param>
public void Add<T1, T2>(Object func)
{
objects.Add(new Tuple<Type, Type, Object>(typeof(T1), typeof(T2), func));
}
public IEnumerator<Tuple<Type, Type, object>> GetEnumerator()
{
return objects.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return objects.GetEnumerator();
}
}
Entonces, cuando finalmente lo llamamos, lo hacemos con reflexión:
var dependency = DependencyResolver.Current.GetService(search.Item1);
var methodInfo = search.Item2.GetMethod("Invoke");
return (IEnumerable<SearchResult>)methodInfo.Invoke(search.Item3, new Object[] { query, dependency });
No encontré lo que estaba buscando aquí, pero después de leer, creo que podría ser lo que se está pidiendo, así que intento responder.
El problema es que cuando usa Dictionary es un tipo construido cerrado y todos los elementos deben ser del tipo TValue. Veo esta pregunta en varios lugares sin una buena respuesta.
El hecho es que quiero indexar, pero cada elemento tiene un tipo diferente y, basado en el valor de TKey, ya conocemos el tipo. No estoy tratando de pasar el boxeo, sino simplemente tratando de obtener acceso más elegante, algo así como el campo DataSetExtensions. Y no quiero usar dinámica porque los tipos son conocidos y simplemente no se quiere.
Una solución puede ser crear un tipo no genérico que no exponga T en el nivel de clase y, por lo tanto, haga que se cierre la parte de TValue del diccionario. Luego espolvorea con un método fluido para ayudar a la inicialización.
public class GenericObject
{
private object value;
public T GetValue<T>()
{
return (T)value;
}
public void SetValue<T>(T value)
{
this.value = value;
}
public GenericObject WithValue<T>(T value)
{
this.value = value;
return this;
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<string, GenericObject> dict = new Dictionary<string, GenericObject>();
dict["mystring"] = new GenericObject().WithValue<string>("Hello World");
dict["myint"] = new GenericObject().WithValue<int>(1);
int i = dict["myint"].GetValue<int>();
string s = dict["mystring"].GetValue<string>();
}
}
Otra posibilidad es usar la variable dinámica.
Por ejemplo:
Dictionary<string, List<dynamic>> d = new Dictionary<string, List<dynamic>>(); d.Add("Key", new List<dynamic>());
la dinámica dinámica resuelve el tipo en tiempo de ejecución.
Prefiero esta manera de poner tipos genéricos en una colección:
interface IList
{
void Add (object item);
}
class MyList<T> : List<T>, IList
{
public void Add (object item)
{
base.Add ((T) item); // could put a type check here
}
}
class Program
{
static void Main (string [] args)
{
SortedDictionary<int, IList>
dict = new SortedDictionary<int, IList> ();
dict [0] = new MyList<int> ();
dict [1] = new MyList<float> ();
dict [0].Add (42);
dict [1].Add ("Hello"); // Fails! Type cast exception.
}
}
Pero pierde los controles de tipo en el momento de la compilación.
Una de las maneras es crear un valor de diccionario con tipo "objeto" como:
Dictionary<string, object> d = new Dictionary<string, object>();
Entonces, aquí el tipo de datos del objeto se usa como un tipo de datos genérico, puede poner cualquier cosa en esto como un valor.