C # Genérico Instantiation

Todos, tengo un método que devuelve una lista. Este método se usa para devolver los parámetros de SQL StoredProcedures, Views y Functions dependiendo del nombre. Lo que quiero hacer es crear una lista de objetos y devolver esta lista a la persona que llama. El método está debajo

private List GetInputParameters(string spFunViewName)
{
    string strSql = String.Format(
        "SELECT PARAMETER_NAME, DATA_TYPE FROM INFORMATION_SCHEMA.PARAMETERS " +
        "WHERE SPECIFIC_NAME = '{0}' AND PARAMETER_MODE = 'IN';",
        spFunViewName);
    List paramInfoList = new List();
    DataTable paramDt = Utilities.DTFromDB(conn, "InputParmaters", strSql);
    if (paramDt != null)
    {
        Converter rowConverter =
            new Converter(Utilities.RowColConvert);
        paramInfoList = Utilities.ConvertRowsToList(paramDt, rowConverter);
    }
    else
        return null;

   //Build the input parameter list.
    List paramList = new List();
    foreach (string[] paramInfo in paramInfoList)
    {
        T t = new T(paramInfo[NAME], paramInfo[TYPE], Convert.ToInt32(paramInfo[CHARMAXLEN]));
        columnList.Add(column);
    }
    return columnList;   
}

I claramente no puede instanciar T a través de new y pasar al constructor, pero debe quedar claro lo que estoy intentando hacer. ¿Hay alguna manera de hacer lo que quiero sin tres métodos adicionales?

Nota. El problema principal es que la cantidad de parámetros que paso a T puede ser dos O tres.

Gracias por tu tiempo.

Editar: Las struct s que uso son las siguientes

public struct Database
{
    public string name { get; set; }
    public string filename { get; set; }
    public List<table> tables { get; set; }
    public List sps { get; set; }
    public List funcs { get; set; }
    public List views { get; set; }
    public Database(string name, string filename)
    {
        this.name = name;
        this.filename = filename;
    }
}

protected internal struct StoredProcedure
{
    public string name { get; set; }
    public List parameters { get; set; }
    public StoredProcedure(string name, List parameters)
    {
        this.name = name;
        this.parameters = parameters;
    }
}

protected internal struct Function
{
    public string name { get; set; }
    public string output { get; set; }
    public List parameters { get; set; }
    public Function(string name, string output, List parameters)
    {
        this.name = name;
        this.output = output;
        this.parameters = parameters;
    }
}

protected internal struct View
{
    public string name {get; set;} 
    public List parameters { get; set; }
    public View(string name, List parameters)
    {
        this.name = name;
        this.parameters = parameters;
    }
}
0
Supongo que "InputParmaters" es un error tipográfico?
agregado el autor comecme, fuente
@Jon Skeet, en realidad es una struct . Estoy intentando construir una estructura de árbol reutilizable para mostrar bases de datos, tablas, etc. pero también quiero poder utilizar la información obtenida de este procedimiento nuevamente, así que utilizo un patrón singleton con struct StoredProcedure , struct Function etc. Gracias.
agregado el autor MoonKnight, fuente
@JonSkeet, a la derecha, no necesito hacer eso, el ciclo es redundante. Pero todavía tengo el problema de que el constructor para T puede tener dos O tres parámetros. Leeré ese artículo gracias por la referencia. Espero que las nuevas ventas de libros vayan bien ...
agregado el autor MoonKnight, fuente
@JonSkeet, gracias por su tiempo aquí. T en este caso será cualquiera de las struct anteriores (ya sea StoredProcedure , Function o View ). ¿Por qué en este caso deberían ser clases? Pensé que ya que estoy creando el objeto de base de datos solo una vez esto estaría bien. Sin embargo, puedo ver que esto podría contener un poco de información ...
agregado el autor MoonKnight, fuente
@Jon Skeet, lo siento, eso no estaba claro. Solo quiero realizar esta operación una vez, así que tengo una clase que construye la información del árbol y la conserva, reconstruyendo solo si elimino el singleton. Dentro de esta clase tengo estructuras que definen los atributos (tabla, sus columnas, sps, funciones y vista (junto con sus parámetros)). las funciones tienen parámetros de entrada y salida, las vistas y sps no ...
agregado el autor MoonKnight, fuente
@comecme No, no lo es.
agregado el autor MoonKnight, fuente
El problema que tengo es que he pasado tantos años escribiendo FORTRAN que a menudo me resulta difícil ver cuál es el mejor enfoque de OOP ...
agregado el autor MoonKnight, fuente
@Killercam: Pero un parámetro no es un procedimiento almacenado, ni es una función. ¿Por qué no tienes un tipo para representar parámetros y luego lo utilizas con composición para procedimientos almacenados, etc. No está claro dónde entra el patrón singleton, pero yo ' Evitarlo fuertemente si fuera usted ... y la idea de una estructura singleton no tiene sentido comenzar con :(
agregado el autor Jon Skeet, fuente
@Killercam: Pero no has mostrado lo que querrías que fuera T (que representa un parámetro por lo que puedo ver). Ah, y esas estructuras parecen que deberían realmente ser clases.
agregado el autor Jon Skeet, fuente
@Killercam: pero estás creando una instancia de T para cada parámetro , lo cual no es correcto si T es un procedimiento almacenado o función, ¿o sí? En cuanto a por qué estas deberían ser clases, lea msdn.microsoft.com/en-us /library/ms229017.aspx
agregado el autor Jon Skeet, fuente
¿Qué es el tipo de T que probablemente esté aquí?
agregado el autor Jon Skeet, fuente
@Killercam: No veo que tengas ningún problema. Su método está destinado a devolver los parámetros , así que haga que haga eso. El que llama puede construir el StoredProcedure/Function/whatever. Trate de evitar hacer demasiado en un solo método.
agregado el autor Jon Skeet, fuente
Para seguir a Jon Skeet, podría poner una restricción genérica para que T siempre sea compatible con un constructor que le gustaría usar. O bien, si siempre es la misma estructura, simplemente conviértala en una list
agregado el autor Aphelion, fuente

7 Respuestas

Puede crear parámetros de base de datos genéricos (y conexiones y comandos, etc.) con ADO.NET DbProviderFactories .

El espacio de nombres System.Data.Common proporciona clases para crear   Instancias de DbProviderFactory para trabajar con orígenes de datos específicos. Cuando   crea una instancia de DbProviderFactory y le pasa información sobre   el proveedor de datos, DbProviderFactory puede determinar el correcto,   fuertemente tipado objeto de conexión para devolver en función de la información que   ha sido provisto.

En su código, podría crear un DbProviderFactory y luego llamar a CreateParameter() .

string providerName = ConfigurationManager.ConnectionStrings["YourConnectionString"].ProviderName;
DbProviderFactory factory = DbProviderFactories.GetFactory(providerName);
DbParameter parameter = factory.CreateParameter();
0
agregado

You could just use List<DbParameter>

Eso es un poco más obvio.

0
agregado

You can use Activator.CreateInstance() as other mentioned or pass a delegate Func avoiding the reflection overhead .

 List GetInputParameters(string spFunViewName, Func itemCreator)
 {

    ....
    List paramList = new List();     
    foreach (string[] paramInfo in paramInfoList)     
    {         
       T t = itemCreator(paramInfo[NAME], paramInfo[TYPE], 
            Convert.ToInt32(paramInfo[CHARMAXLEN]));         
      paramList.Add(t);     
    }     

    return columnList;    
 }
0
agregado

Puedes intentar esto:

var constructor = typeof(T).GetConstructor(typeof(string), typeof(string), typeof(int));
constructor.Invoke(colInfo[NAME], colInfo[TYPE], Convert.ToInt32(colInfo[CHARMAXLEN]));
0
agregado

Use la clase Activator para crear T y pase los parámetros.

Type type = typeof(T);
var result = (T)Activator.CreateInstance(type, new object[] { yourParameters });

Usado en tu fragmento de código:

T t = Activator.CreateInstance(type, colInfo[NAME], colInfo[TYPE], Convert.ToInt32(colInfo[CHARMAXLEN]));
0
agregado
Ok, lo he hecho. Gracias de nuevo por tu tiempo...
agregado el autor MoonKnight, fuente
Perdón por esto. Esto me parece nuevo. ¿Estás diciendo envolver las estructuras múltiples en una sola clase y usar eso?
agregado el autor MoonKnight, fuente
En esta etapa, no estoy seguro de por qué? ¿Me puedes cantar? Tengo tres tipos, sps, funciones y vistas. remolque de estos tienen solo parámetros de entrada (sp y vistas), las funciones tienen ambos ...
agregado el autor MoonKnight, fuente
Increíble, no sabía nada de esto, muchas gracias por su tiempo ...
agregado el autor MoonKnight, fuente
@Killercam No hay problema. Sin embargo, como otros han escrito, es mejor evitar esto y utilizar un appproach diseñado diferente.
agregado el autor Aphelion, fuente
Bueno, he leído que usas estructuras. Sin embargo, podrías buscar o crear una superclase con el constructor y ponerla como una restricción en T. Entonces no tienes que usar el activador.
agregado el autor Aphelion, fuente
Es mejor publicar un ejemplo del tipo de estructuras que tienes en la pregunta;). Por ahora no puedo estar seguro.
agregado el autor Aphelion, fuente

No estoy avalando ni menospreciando esta técnica, pero puedes usar:

(T) Activator.CreateInstance( typeof(T), colInfo[TYPE], Convert.ToInt32(colInfo[CHARMAXLEN]) );

Creo que preferiría tener métodos de fábrica separados.

0
agregado

Claramente no puedo instalar T a través de nuevo y pasar al constructor

Como está escrito, no; sin embargo, puede puede si restringe su parámetro de tipo para aceptar solo tipos con constructores:

private List GetInputParameters(string spFunViewName) where T : new()
{
   //your code here
}

En el ejemplo anterior, podrías decir:

T myItem = new T();

En su caso específico, parece que espera que cada uno de los tipos genéricos comparta algo en común. Considere también restringir el tipo con una interfaz:

private List GetInputParameters(string spFunViewName) where T : new(), ISomeInterface
{
   //your code here
}

Eso le permitiría, después de instanciar su objeto, aplicar valores a cualquier propiedad en la interfaz:

T myItem = new T();

myItem.SomeProperty = somevalue;
myItem.AnotherProperty = anothervalue;

Para obtener más información, consulte Restricciones sobre los parámetros de tipo ( C# Programming Guide) en MSDN para obtener más información sobre las restricciones de tipo genérico.

0
agregado
Esto ha sido hecho ...
agregado el autor MoonKnight, fuente
¡Me gusta esto muchisimo! Pero, ¿el hecho de que los objetos dentro de mis tres estructuras no sean diferentes significa que no puedo usar una interfaz ya que es todo o nada?
agregado el autor MoonKnight, fuente
Idealmente, en este caso, cada una de las estructuras (o clases) podría implementar (o heredar) la misma interfaz o clase base, si no otra cosa, simplemente algo con un método de fábrica. ¿Sería capaz de actualizar su pregunta para incluir las estructuras reales?
agregado el autor Steve Konves, fuente
agregado el autor Steve Konves, fuente