【问题标题】:C# Generics InstantiationC# 泛型实例化
【发布时间】:2012-06-22 02:38:21
【问题描述】:

所有,我有一个返回列表的方法。该方法用于根据名称返回 SQL StoredProcedures、Views 和 Functions 的参数。我想要做的是创建一个对象列表并将这个列表返回给调用者。方法如下

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

显然无法通过new 实例化T 并传递给构造函数,但应该清楚我正在尝试做什么。有没有办法在没有另外三种方法的情况下做我想做的事?

注意。主要问题是我传递给 T 的参数数量可以是两个 OR 三。

感谢您的宝贵时间。

编辑:我使用的structs如下

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

【问题讨论】:

  • T 的类型可能出现在这里?
  • @Jon Skeet,实际上是struct。我正在尝试构建一个可重用的树结构来显示数据库、表等,但我也希望能够再次使用从这个过程中获得的信息 - 所以我使用带有 struct StoredProcedurestruct Function 等的单例模式。谢谢.
  • 我想"InputParmaters" 是错字?
  • 我遇到的问题是,我花了这么多年时间编写 FORTRAN,以至于我经常发现很难看到最好的 OOP 方法是什么......
  • @Killercam:我看不出你有什么问题。您的方法旨在返回 parameters,所以让它这样做。然后调用者可以构造 StoredProcedure/Function/whatever。尽量避免在单一方法中做太多事情。

标签: c# generics


【解决方案1】:

使用Activator类创建T并传递参数。

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

在你的代码sn-p中使用:

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

【讨论】:

  • @Killercam 没问题。然而,正如其他人所写的那样,最好避免这种情况并使用不同的设计方法。
  • 现阶段我不知道为什么?你能幽默我吗?我有三种类型,sps,函数和视图。其中两个只有输入参数(sp 和视图),函数都有...
  • 好吧,我现在读到你使用结构。但是,您可以使用构造函数搜索或创建超类,并将其作为 T 的约束。然后您不必使用激活器。
  • 对此感到抱歉。这对我来说似乎很新鲜。您是说将多个结构包装在一个类中并使用它吗?
  • 最好发布一个您在问题中拥有的那种结构的示例;)。现在我不能确定。
【解决方案2】:

我既不赞同也不贬低这种技术,但你可以使用:

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

我想我宁愿有单独的工厂方法。

【讨论】:

    【解决方案3】:

    您可以像其他提到的那样使用Activator.CreateInstance() 或传递一个委托Func&lt;string, string, int, T&gt; 避免反射开销。

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

    【讨论】:

      【解决方案4】:

      我显然不能通过 new 实例化 T 并传递给构造函数

      正如所写,不;但是,如果您将类型参数限制为仅接受带有构造函数的类型,您可以

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

      在上面的例子中,你可以说:

      T myItem = new T();
      

      在您的特定情况下,您似乎希望每个泛型类型共享一些共同点。还可以考虑使用接口约束类型:

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

      这将允许您在实例化对象后,将值应用于接口上的任何属性:

      T myItem = new T();
      
      myItem.SomeProperty = somevalue;
      myItem.AnotherProperty = anothervalue;
      

      有关更多信息,请查看 MSDN 上的 Constraints on Type Parameters (C# Programming Guide),了解有关泛型类型约束的更多信息。

      【讨论】:

      • 我非常喜欢这个!但是,我的三个结构中的对象不同这一事实是否意味着我不能使用接口,因为它是全有或全无?
      • 理想情况下,在这种情况下,每个结构(或类)都能够实现(或继承自)相同的接口或基类,如果没有别的,只是具有工厂方法的东西。您能否更新您的问题以包含实际结构?
      【解决方案5】:

      你可以只使用 ListDbParameter>

      这有点明显。

      【讨论】:

        【解决方案6】:

        你可以试试这个:

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

        【讨论】:

          【解决方案7】:

          您可以使用 ADO.NET DbProviderFactories 创建通用数据库参数(以及连接和命令等)。

          System.Data.Common 命名空间提供用于创建的类 DbProviderFactory 实例与特定数据源一起工作。什么时候 您创建一个 DbProviderFactory 实例并传递有关信息 数据提供者,DbProviderFactory 可以判断正确, 强类型连接对象根据它返回的信息 已提供。

          在您的代码中,您可以创建一个DbProviderFactory,然后调用CreateParameter()

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

          【讨论】:

            猜你喜欢
            • 2023-03-19
            • 2013-10-03
            • 2011-04-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多