2012-06-21 15 views
7

Wszystko, mam metodę, która zwraca listę. Ta metoda służy do zwracania parametrów SQL StoredProcedures, widoków i funkcji w zależności od nazwy. Co chcę zrobić, to utworzyć listę obiektów i zwrócić tę listę do dzwoniącego. Metoda ta jest poniżejC# Generics Natychmiastowa

private List<T> GetInputParameters<T>(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<string[]> paramInfoList = new List<string[]>(); 
    DataTable paramDt = Utilities.DTFromDB(conn, "InputParmaters", strSql); 
    if (paramDt != null) 
    { 
     Converter<DataRow, string[]> rowConverter = 
      new Converter<DataRow, string[]>(Utilities.RowColConvert); 
     paramInfoList = Utilities.ConvertRowsToList<string[]>(paramDt, rowConverter); 
    } 
    else 
     return null; 

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

I wyraźnie może nie wystąpienia T poprzez new i przekazać do konstruktora, ale powinno być jasne, co ja próbuje zrobić. Czy istnieje sposób robienia tego, co chcę, przy pomocy trzech dodatkowych metod?

Uwaga. Głównym problemem jest to, że liczba parametrów, które przechodzę do T, może wynosić trzy: OR.

Dzięki za poświęcony czas.

EDIT: struct s używam są następujące

public struct Database 
{ 
    public string name { get; set; } 
    public string filename { get; set; } 
    public List<Table> tables { get; set; } 
    public List<StoredProcedure> sps { get; set; } 
    public List<Function> funcs { get; set; } 
    public List<View> 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<string[]> parameters { get; set; } 
    public StoredProcedure(string name, List<string[]> parameters) 
    { 
     this.name = name; 
     this.parameters = parameters; 
    } 
} 

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

protected internal struct View 
{ 
    public string name {get; set;} 
    public List<string[]> parameters { get; set; } 
    public View(string name, List<string[]> parameters) 
    { 
     this.name = name; 
     this.parameters = parameters; 
    } 
} 
+0

Co to jest * typ "T", który może być tutaj? –

+0

@Jon Skeet, W rzeczywistości jest to 'struct'. Próbuję zbudować strukturę drzewa wielokrotnego użytku, aby wyświetlić bazy danych, tabele itp., Ale chcę również móc ponownie korzystać z informacji uzyskanych z tej procedury - dlatego używam wzorca singleton z 'struct StoredProcedure',' struct Function' etc . Dzięki. – MoonKnight

+0

Przypuszczam, że '" InputParmaters "' jest literówka? – comecme

Odpowiedz

6

użyć klasy Activator stworzyć T i przekazać parametry.

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

Używany w fragmencie kodu:

T t = Activator.CreateInstance(type, colInfo[NAME], colInfo[TYPE], Convert.ToInt32(colInfo[CHARMAXLEN])); 
+0

Niesamowite, nie wiedziałem o tym w ogóle, bardzo dziękuję za poświęcony czas ... – MoonKnight

+0

@Killercam Bez problemu. Jednak, jak napisali inni, najlepiej tego unikać i używać innego zaprojektowanego podejścia. – Aphelion

+0

Na tym etapie nie jestem pewien, dlaczego? Czy możesz mnie zabawiać? Mam trzy typy, sps, funkcje i widoki. ciąg te mają tylko parametry wejściowe (sp i widoki), funkcje mają zarówno ... – MoonKnight

3

jestem ani popierając ani szkody dla tej techniki, ale można użyć:

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

myślę wolałbym mieć oddzielny metody fabryczne.

1

mógłby po prostu użyć Lista < DbParameter>

To jest nieco bardziej oczywiste.

1

Można spróbować to:

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

Można użyć Activator.CreateInstance() jak pozostałe wymienione lub przekazać delegatowi Func<string, string, int, T> unika napowietrznej refleksji.

List<T> GetInputParameters<T>(string spFunViewName, Func<string, string, int, T> itemCreator) 
{ 

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

    return columnList;  
} 
1

Można tworzyć ogólnych parametrów bazy danych (i połączeń i poleceń, etc) z ADO.NET DbProviderFactories.

Przestrzeń nazw System.Data.Common zapewnia klas do tworzenia DbProviderFactory instancji do pracy z określonymi źródłami danych. Po utworzeniu instancji DbProviderFactory i przesłaniu jej informacji o dostawcy danych, DbProviderFactory może określić poprawny, mocno wpisany obiekt połączenia, który ma zostać zwrócony na podstawie informacji podanych przez dostawcę D2P2.

W swoim kodzie możesz utworzyć DbProviderFactory, a następnie zadzwonić pod numer CreateParameter().

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

I wyraźnie nie może instansiate T poprzez nowe i przekazać do konstruktora

jak napisano, nie; Jednak może jeśli ograniczyć swój parametr typu przyjąć tylko typy z konstruktorów:

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

W powyższym przykładzie będzie można powiedzieć:

T myItem = new T(); 

W Twoim konkretnym przypadku, Wygląda na to, że oczekujesz, że każdy z typów ogólnych ma coś wspólnego. Zastanów się również ograniczać typ z interfejsem:

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

To pozwoli Ci, po instancji nie zgadzasz, stosuje się wartości do jakichkolwiek właściwości w interfejsie:

T myItem = new T(); 

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

Aby uzyskać więcej informacji, sprawdź Constraints on Type Parameters (C# Programming Guide) w witrynie MSDN, aby uzyskać więcej informacji na temat ograniczeń typu ogólnego.

+0

Podoba mi się to dużo! Ale czy fakt, że obiekty wewnątrz moich trzech struktur jest inny, nie oznacza, że ​​nie mogę korzystać z interfejsu, ponieważ jest on całkowicie lub nic? – MoonKnight

+0

Idealnie, w tym przypadku, każda ze struktur (lub klas) byłaby w stanie zaimplementować (lub dziedziczyć) ten sam interfejs lub klasę podstawową, jeśli nic innego, po prostu coś z metodą fabryczną. Czy byłbyś w stanie zaktualizować swoje pytanie, aby uwzględnić faktyczne struktury? –

+0

To zostało zrobione ... – MoonKnight