2010-06-16 137 views
45

映射類錯誤'T'必須是具有公共無參數構造函數的非抽象類型才能用作泛型類型或方法中的參數'T'。類映射錯誤:'T'必須是具有公共無參數構造函數的非抽象類型

下面是我SqlReaderBase類

public abstract class SqlReaderBase<T> : ConnectionProvider 
    { 

     #region Abstract Methods 

     protected abstract string commandText { get; } 
     protected abstract CommandType commandType { get; } 
     protected abstract Collection<IDataParameter> GetParameters(IDbCommand command); 
     **protected abstract MapperBase<T> GetMapper();** 

     #endregion 

     #region Non Abstract Methods 

     /// <summary> 
     /// Method to Execute Select Queries for Retrieveing List of Result 
     /// </summary> 
     /// <returns></returns> 
     public Collection<T> ExecuteReader() 
     { 
      //Collection of Type on which Template is applied 
      Collection<T> collection = new Collection<T>(); 

      // initializing connection 
      using (IDbConnection connection = GetConnection()) 
      { 
       try 
       { 
        // creates command for sql operations 
        IDbCommand command = connection.CreateCommand(); 

        // assign connection to command 
        command.Connection = connection; 

        // assign query 
        command.CommandText = commandText; 

        //state what type of query is used, text, table or Sp 
        command.CommandType = commandType; 

        // retrieves parameter from IDataParameter Collection and assigns it to command object 
        foreach (IDataParameter param in GetParameters(command)) 
         command.Parameters.Add(param); 


        // Establishes connection with database server 
        connection.Open(); 

        // Since it is designed for executing Select statements that will return a list of results 
        // so we will call command's execute reader method that return a Forward Only reader with 
        // list of results inside. 
        using (IDataReader reader = command.ExecuteReader()) 
        { 
         try 
         { 
          // Call to Mapper Class of the template to map the data to its 
          // respective fields 
          MapperBase<T> mapper = GetMapper(); 
          collection = mapper.MapAll(reader); 

         } 
         catch (Exception ex)   // catch exception 
         { 
          throw ex;  // log errr 
         } 
         finally 
         { 
          reader.Close(); 
          reader.Dispose(); 
         } 
        } 
       } 
       catch (Exception ex) 
       { 
        throw ex; 
       } 
       finally 
       { 
        connection.Close(); 
        connection.Dispose(); 
       } 
      } 
      return collection; 
     } 
     #endregion 
    } 

我所試圖做的是,我executine一些命令和動態填充我的課。下面類中給出:

namespace FooZo.Core 
{ 
    public class Restaurant 
    { 


     #region Private Member Variables 
     private int _restaurantId = 0; 
     private string _email = string.Empty; 
     private string _website = string.Empty; 
     private string _name = string.Empty; 
     private string _address = string.Empty; 
     private string _phone = string.Empty; 
     private bool _hasMenu = false; 
     private string _menuImagePath = string.Empty; 
     private int _cuisine = 0; 
     private bool _hasBar = false; 
     private bool _hasHomeDelivery = false; 
     private bool _hasDineIn = false; 
     private int _type = 0; 
     private string _restaurantImagePath = string.Empty; 
     private string _serviceAvailableTill = string.Empty; 
     private string _serviceAvailableFrom = string.Empty; 

     public string Name 
     { 
      get { return _name; } 
      set { _name = value; } 
     } 

     public string Address 
     { 
      get { return _address; } 
      set { _address = value; } 
     } 
     public int RestaurantId 
     { 
      get { return _restaurantId; } 
      set { _restaurantId = value; } 
     } 
     public string Website 
     { 
      get { return _website; } 
      set { _website = value; } 
     } 

     public string Email 
     { 
      get { return _email; } 
      set { _email = value; } 
     } 
     public string Phone 
     { 
      get { return _phone; } 
      set { _phone = value; } 
     } 

     public bool HasMenu 
     { 
      get { return _hasMenu; } 
      set { _hasMenu = value; } 
     } 

     public string MenuImagePath 
     { 
      get { return _menuImagePath; } 
      set { _menuImagePath = value; } 
     } 

     public string RestaurantImagePath 
     { 
      get { return _restaurantImagePath; } 
      set { _restaurantImagePath = value; } 
     } 

     public int Type 
     { 
      get { return _type; } 
      set { _type = value; } 
     } 

     public int Cuisine 
     { 
      get { return _cuisine; } 
      set { _cuisine = value; } 
     } 

     public bool HasBar 
     { 
      get { return _hasBar; } 
      set { _hasBar = value; } 
     } 

     public bool HasHomeDelivery 
     { 
      get { return _hasHomeDelivery; } 
      set { _hasHomeDelivery = value; } 
     } 

     public bool HasDineIn 
     { 
      get { return _hasDineIn; } 
      set { _hasDineIn = value; } 
     } 

     public string ServiceAvailableFrom 
     { 
      get { return _serviceAvailableFrom; } 
      set { _serviceAvailableFrom = value; } 
     } 

     public string ServiceAvailableTill 
     { 
      get { return _serviceAvailableTill; } 
      set { _serviceAvailableTill = value; } 
     } 


     #endregion 

     public Restaurant() { } 

    } 
} 

爲了填充我的類屬性動態我有稱爲MapperBase類具有下列方法另一個類:

public abstract class MapperBase<T> where T : new() 
    { 
     protected T Map(IDataRecord record) 
     { 
      T instance = new T(); 

      string fieldName; 
      PropertyInfo[] properties = typeof(T).GetProperties(); 

      for (int i = 0; i < record.FieldCount; i++) 
      { 
       fieldName = record.GetName(i); 

       foreach (PropertyInfo property in properties) 
       { 
        if (property.Name == fieldName) 
        { 
         property.SetValue(instance, record[i], null); 
        } 
       } 
      } 

      return instance; 
     } 
     public Collection<T> MapAll(IDataReader reader) 
     { 
      Collection<T> collection = new Collection<T>(); 

      while (reader.Read()) 
      { 

        collection.Add(Map(reader)); 

      } 

      return collection; 
     } 

    } 

有承接所述SqlreaderBaseClass稱爲DefaultSearch另一個類。代碼如下

public class DefaultSearch: SqlReaderBase<Restaurant> 
{ 
    protected override string commandText 
    { 
     get { return "Select Name from vw_Restaurants"; } 
    } 

    protected override CommandType commandType 
    { 
     get { return CommandType.Text; } 
    } 

    protected override Collection<IDataParameter> GetParameters(IDbCommand command) 
    { 
     Collection<IDataParameter> parameters = new Collection<IDataParameter>(); 
     parameters.Clear(); 
     return parameters; 
    } 



    protected override MapperBase<Restaurant> GetMapper() 
    { 
     MapperBase<Restaurant> mapper = new RMapper(); 
     return mapper; 
    } 
} 

但每當我試圖建立,我收到錯誤「T」必須是爲了在泛型類型使用它作爲參數「T」非抽象類型具有公共的無參數的構造函數或方法。即使這裏的T餐廳有一個無參數公共構造函數。

回答

85

的問題是,你要使用TSqlReaderBase作爲類型參數的MapperBase - 但你不必對T任何約束。

試着改變你的SqlReaderBase聲明如下:

public abstract class SqlReaderBase<T> : ConnectionProvider 
    where T : new() 

這裏有一個較短的例子說明了同一個問題:

class Foo<T> 
{ 
    Bar<T> bar; 
} 

class Bar<T> where T : new() 
{ 
} 

的修復方法就是改變Foo<T>的宣言:

class Foo<T> where T : new() 

然後編譯器會知道012來自Foo的是Bar的有效類型參數。

+0

感謝它的工作。但還有一件事是有沒有辦法在SqlReaderBase本身中調用MapperBase 而不創建受保護的抽象映射表 GetMapper();方法。 – 2010-06-16 20:37:37

+1

@Amit:你可以有一個*分開的*類型參數'TMapper',約束:'其中TMapper:MapperBase ,new()' – 2010-06-16 20:43:24

+0

請給我提供實際的聲明..這將是一個gr8的幫助 – 2010-06-16 20:49:37

9

約束必須適用於鏈中的每個類型;因此,你需要:

public abstract class SqlReaderBase<T> : ConnectionProvider where T : new() 

如果沒有這個,你不能滿足約束爲T在:

protected abstract MapperBase<T> GetMapper(); 

MapperBase<T> mapper = GetMapper(); 

因爲MapperBase<>T只有可用: new()

+0

你的解決方案工作的人。但Jon的評論中還有一個問題 – 2010-06-16 20:38:21

1

我有同樣的問題。在谷歌搜索之前,我應該閱讀這條消息。我需要添加一個無參數的構造函數...:-)

public MyClass() { 
    //stuff 
} 
相關問題