Tengo un método, no tiene ningún parámetro T.

Desafortunadamente, el operador de tipo C # no funciona con genéricos como se muestra a continuación.

public static string ToString(object obj)
{
    if (obj.GetType() == typeof(List<object>))
    {
        return "Bug: Never called";
    }
    if (obj.GetType() == typeof(List<int>))
    {
        return "Method only works for int lists";
    }
    return "";
}

Resultado esperado: ToString (Lista de entradas) devolvería "Error: Nunca llamado".

Resultado real: "El método solo funciona para listas int"

Esto funcionó perfectamente bien en Java. Dirás que los genéricos en c # no son compatibles con esto. ¿Cómo puedo reestructurar mi código para que el método "ToString (objeto)" funcione para una lista de objetos?

Requisitos: No se puede modificar la firma del método, solo su implementación.

Desafortunadamente, no puede hacer que la clase "int" implemente una interfaz. Dado que la clase int fue escrita por Microsoft. Como tal, no puedo agregar un patrón de visitante en el tipo int.

4
user2186597 10 dic. 2016 a las 11:09
¿Por qué espera un List<int> que devuelva "Bug: Never Called", que es la rama de List<object>?
 – 
Bill Tür
10 dic. 2016 a las 11:23
2
No entiendo por qué espera que el tipo de objeto List<int> sea List<object>. Sí, eso es lo que hace Java, pero C # no es Java. Podría decirse que el comportamiento de Java no es lo que la mayoría de la gente espera. Supongo que podría usar GetGenericTypeDefintion y comparar con typeof(List<>) para ver si es una lista de algo.
 – 
Mike Zboray
10 dic. 2016 a las 11:25
Porque object es la superclase de int. También pensé que el objeto "captura" int.
 – 
user2186597
10 dic. 2016 a las 11:48
- object es la superclase de int.
 – 
Enigmativity
10 dic. 2016 a las 12:07
1
- El hecho de que int se derive de object no significa que List<int> se derive de List<object>.
 – 
Enigmativity
10 dic. 2016 a las 12:08

1 respuesta

La mejor respuesta

Desafortunadamente, el operador c # typeof no funciona en genéricos como se muestra a continuación.

De hecho, es una suerte que no funcione como esperabas. A diferencia de Java, C # diferencia entre List<int> y List<object> en tiempo de ejecución, no solo en tiempo de compilación. La información de tipo para genéricos instanciados con parámetros de tipo primitivo permite que .NET produzca código más eficiente al evitar el borrado de tipo.

Si desea probar si un objeto es cualquier lista genérica, utilice esta verificación en su lugar:

var objT = obj.GetType();
if (objT.IsGenericType && objT.GetGenericTypeDefinition() == typeof(List<>)) {
    ...
}

Como tal, no puedo agregar un patrón de visitante en el tipo int.

C # le brinda un mecanismo poderoso para distribuir dinámicamente sin implementar una interfaz. Por ejemplo, puede hacer esto:

public static string ToString(object obj) {
    var list = obj as IList;
    if (list != null) {
        foreach (dynamic o in list) {
            Process(o);
        }
    }
}
static void Process(int n) { ... }
static void Process(string s) { ... }
static void Process(object o) { ... }

Lo anterior elegirá la implementación correcta de Process según el tipo de tiempo de ejecución del objeto en su lista.

8
Sergey Kalinichenko 10 dic. 2016 a las 12:04
Genial, respondió la primera parte de la pregunta, ¿por qué los genéricos de C # no funcionan de esa manera? Ahora, para la segunda parte de la pregunta: solo quiero manipular la lista de manera uniforme independientemente del tipo subyacente.
 – 
user2186597
10 dic. 2016 a las 11:53
Cualquier lista genérica: D
 – 
Matías Fidemraizer
10 dic. 2016 a las 11:53
Dasblinkenlight, eso es bueno, pero la conversión arrojará una excepción si el objeto subyacente no es una lista. Por eso me concentré en la "condición si".
 – 
user2186597
10 dic. 2016 a las 12:09