2010-01-05 31 views
5

Oye, creo que tengo una idea equivocada aquí, pero no estoy seguro de qué es lo mejor. Quiero una clase con una variable miembro que puede ser de cualquier tipo, dependiendo de lo que se necesite en ese momento. Hasta el momento, tengo algo como esto:¿Miembros genéricos de la clase en C#?

public class ConfigSetting<T> { 
    private T value; 

    public T GetValue() { 
     return value; 
    } 
    public void ChangeValue() { 

    } 

    public ConfigSetting(string heading, string key) { 
     this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
    } 
} 

El tipo devuelto por el lado derecho de la línea 'this.value' es una cadena, en la actualidad. Sé que parece que no necesito usar nada más que el tipo de cadena, pero eventualmente expandiré el constructor, de modo que 'this.value' podría ser una cadena, int, float o bool.

De todos modos, mi compilador dice "No se puede convertir 'cadena' a 'T'", así que supongo que estoy haciendo algo muy al revés.

Gracias.

Respuesta

6

Bueno, ¿qué esperabas de conversión que se aplique? Si espera que el valor de ya sea del tipo adecuado, se podría hacer:

object tmp = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
this.value = (T) tmp; 

en cuenta que tiene que pasar por object de forma implícita (como en este caso) o con una conversión explícita:

this.value = (T)(object) DerivedMethods.configsettings... (etc); 

El conjunto de conversiones proporcionadas para los tipos genéricos es algo limitado. Pero debería funcionar si el valor original es genuinamente correcto.

+1

Gracias. Esto compila (aunque todavía tengo que probarlo). Tengo dos preguntas: 1: ¿Por qué tengo que pasar por el objeto? 2: ¿Qué sucede después de esto si trato de usar métodos de cadena en el valor? ¿Sabe C# ahora que el valor es de tipo String? – Xenoprimate

+1

no RawValue siempre devuelve una cadena? ¿no fallaría la conversión a int, long, etc? – bendewey

+0

Sí, pero como dije en mi pregunta original, tengo la intención de expandir el constructor. – Xenoprimate

2

, es necesario especificar la cadena devuelta a T:

public ConfigSetting(string heading, string key) { 
    this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
} 
+0

Esto no funciona, el mismo error. Hubiera dicho que ya lo había intentado, pero supuse que el problema era más profundo que esto. – Xenoprimate

0

Parece que está intentando asignar una cadena (configsettings.SettingGroups[heading].Settings[key].RawValue) al miembro genérico. Necesitarás proporcionar alguna forma de convertir la cuerda a tipo T, generalmente a través de la fundición. Por ejemplo:

this.value = (T)DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
0

En esta línea:

this.value = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 

está configurando la variable de tipo T a un valor de cadena. El método RawValue devuelve una cadena. Debe convertirlo explícitamente en tipo T.

this.value = (T) (object) DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 

¿Realmente solo tendré T valores sin constructores? Es posible que pueda hacerlo explícito y evitar el objeto fundición, si desea evitar eso por alguna razón.

1

Creo que no necesariamente debe usar genéricos para planificar con anticipación todos los posibles escenarios futuros porque es probable que se encuentre con casos extremos en el futuro y tenga que modificar el código independientemente.

Sin embargo, si ya tiene varias situaciones en las que un genérico podría ajustarse, entonces puede beneficiarse de la reutilización de la lógica ahora y puede probarlas todas correctamente.

Veo que otros ya han proporcionado respuestas de código, así que me detendré aquí.

1

que asumen que

DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue 

es una cadena.

No se puede asignar una cadena a this.value porque el tipo de this.value es T y podría ser cualquier cosa, como por ejemplo los tipos a los que las cadenas no son asignables.

Una solución es eliminar un parámetro genérico y hacer value una cadena, y luego proporcionar diferentes formas de acceder a ella que analizan bools, flotantes o lo que sea necesario.

public float GetFloatValue { 
    get { return float.Parse(this.value); } 
} 

// etc 
0

Pruebe con un

string strValue = DerivedMethods.configsettings.SettingGroups[heading].Settings[key].RawValue; 
this.value = (T)Convert.ChangeType(strValue, typeof(T), CultureInfo.InvariantCulture) 

si tiene sus valores de configuración almacenados como cadenas y quiere que se convierte en el tipo correcto. Esto solo funciona para la mayoría de los tipos primitivos como Int32, Doble, etc.

7

Te encuentras con problemas porque este no es un buen uso de los genéricos. Si el parámetro de tipo genérico solo puede construirse de cuatro formas diferentes: cadena, flotante, bool e int, entonces esto no es muy generic. Supongo que una cosa genérica puede ser de cualquier tipo.

Si tuviera una cosa que sólo podía ser uno de los cuatro tipos entonces yo modelarlo como esto:

abstract class ConfigSetting 
{ /* shared code here */ } 

class TextSetting : ConfigSetting 
{ /* Code here to handle string settings */ } 

class BooleanSetting : ConfigSetting 
{ /* ... 

y así sucesivamente. Probablemente les daría a cada uno de ellos un constructor interno y convertiría la clase base en fábrica para las clases derivadas, utilizando el patrón de fábrica.

Solo use genéricos si su solución es realmente generic. Como List<T>, por ejemplo, puede ser una lista de cualquier cosa: ints, cadenas, matrices, diccionarios, funciones, lo que sea. Si lo que está modelando tiene una pequeña cantidad de tipos posibles, solo haga uno para cada tipo.

Cuestiones relacionadas