简体   繁体   English

C#泛型实例化

[英]C# Generics Instantiation

All, I have a method that returns a List. 全部,我有一个返回List的方法。 This method is used to return the parameters of SQL StoredProcedures, Views and Functions depending on name. 此方法用于根据名称返回SQL StoredProcedures,Views和Functions的参数。 What I want to do is create a list of objects and return this list to the caller. 我想要做的是创建一个对象列表并将此列表返回给调用者。 The method is below 方法如下

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 clearly can't instantiate T via new and pass to the constructor, but it should be clear what I am attempting to do. 显然无法通过new实例化T并传递给构造函数,但应该清楚我正在尝试做什么。 Is there a way to do what I want with out three additional methods? 有没有办法用另外三种方法做我想做的事情?

Note. 注意。 The main issue is that the number of parameters I am passing to T can either be two OR three. 主要问题是我传递给T的参数数量可以是两个三个。

Thanks for your time. 谢谢你的时间。

Edit: The struct s I use are as follows 编辑:我使用的struct如下

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;
    }
}

Use the Activator class to create T and pass the parameters. 使用Activator类创建T并传递参数。

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

Used in your code snippet: 在您的代码段中使用:

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

I'm neither endorsing nor detracting this technique, but you can use: 我既不赞同也不贬低这种技巧,但你可以使用:

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

I think I'd rather have separate factory methods. 我想我宁愿有单独的工厂方法。

You can use Activator.CreateInstance() as other mentioned or pass a delegate Func<string, string, int, T> avoiding the reflection overhead . 您可以像其他提到的那样使用Activator.CreateInstance()或传递委托Func<string, string, int, T>避免反射开销。

 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;    
 }

I clearly can't instansiate T via new and pass to the constructor 我显然无法通过new实现T并传递给构造函数

As written, no; 如上所述,不; however, you can if you constrain your type parameter to only accept types with constructors: 但是,你可以 ,如果你限制你的类型参数,只接受类型的构造函数:

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

In the example above you would be able to say: 在上面的例子中,您可以说:

T myItem = new T();

In your specific case, it looks like you expect each of the generic types to share something in common. 在您的特定情况下,您似乎期望每个泛型类型共享一些共同点。 Consider also constraining the type with an interface: 考虑使用接口约束类型:

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

That would allow you to, after you instantiate you object, apply values to any properties on the interface: 这将允许您在实例化对象后,将值应用于接口上的任何属性:

T myItem = new T();

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

For more info, check out Constraints on Type Parameters (C# Programming Guide) on MSDN for more info on generic type constraints. 有关更多信息,请查看MSDN 上的类型参数约束(C#编程指南)以获取有关泛型类型约束的更多信息。

You could just use List< DbParameter > 你可以使用List < DbParameter >

That is a bit more obvious. 这有点明显了。

You could try this: 你可以试试这个:

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

You can create generic database parameters (and connections and commands, etc) with ADO.NET DbProviderFactories . 您可以使用ADO.NET DbProviderFactories创建通用数据库参数(以及连接和命令等)。

The System.Data.Common namespace provides classes for creating DbProviderFactory instances to work with specific data sources. System.Data.Common命名空间提供用于创建DbProviderFactory实例以使用特定数据源的类。 When you create a DbProviderFactory instance and pass it information about the data provider, the DbProviderFactory can determine the correct, strongly typed connection object to return based on the information it has been provided. 当您创建DbProviderFactory实例并向其传递有关数据提供程序的信息时,DbProviderFactory可以根据提供的信息确定要返回的正确的强类型连接对象。

In your code, you could create a DbProviderFactory and then call CreateParameter() . 在您的代码中,您可以创建一个DbProviderFactory ,然后调用CreateParameter()

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM