2010-06-16 9 views
45

Podczas klasy mapowania otrzymuję błąd 'T' musi być typem nie abstrakcyjnym z publicznym konstruktorem bez parametrów w celu użycia go jako parametr "T" w typie generycznym lub metodzie.Błąd odwzorowania klasy: 'T' musi być typem nie abstrakcyjnym z publicznym konstruktorem bez parametrów

Poniżej jest moje SqlReaderBase Klasa

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 
    } 

Co staram się robić to, jestem executine niektóre polecenia i wypełnienie mojej klasy dynamicznie. Klasa jest podana poniżej:

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() { } 

    } 
} 

Do wypełniania swoich właściwości klasy dynamicznie mam inną klasę o nazwie MapperBase klasy z następujących metod:

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

    } 

istnieje inna klasa, która dziedziczy SqlreaderBaseClass nazywa DefaultSearch. Kod jest poniżej

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

Ale ilekroć próbowałem budować, otrzymuję błąd „T” musi być non-abstrakcyjny typ z konstruktora bez parametrów publicznej w celu wykorzystania go jako parametr „T” w rodzaju generycznego lub metoda. Nawet T tutaj jest Restauracja ma Konstruktor bez Parameter Public.

Odpowiedz

85

Problemem jest to, że starasz się używać T z SqlReaderBase jako argumentu typu dla MapperBase - ale nie masz żadnych ograniczeń żeT.

Spróbuj zmienić swoją deklarację SqlReaderBase do tego:

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

Oto krótszy przykład, który pokazuje ten sam problem:

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

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

Rozwiązaniem jest zmiana Foo<T> „s deklarację:

class Foo<T> where T : new() 

Następnie kompilator będzie wiedział, że T z Foo jest poprawnym argumentem typu dla Bar.

+0

Dzięki temu zadziałało. Ale jest jeszcze jeden sposób wywoływania MapperBase w samej SqlReaderBase bez tworzenia Protected Abstract Mapperbase GetMapper(); metoda. –

+1

@Amit: Możesz mieć * oddzielny * parametr typu 'TMapper' z ograniczeniem:' gdzie TMapper: MapperBase , new() ' –

+0

proszę podać mi faktyczną deklarację .. byłoby to gr8 pomoc –

9

Ograniczenia muszą dotyczyć każdego rodzaju łańcucha; Stąd potrzebne są:

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

Bez tego nie można spełnić ograniczenie dla T w:

protected abstract MapperBase<T> GetMapper(); 

lub

MapperBase<T> mapper = GetMapper(); 

od MapperBase<> jest tylko użyteczny gdy ma T: new()

+0

Twoje rozwiązanie zadziałało. Ale wciąż jeszcze jeden problem, opublikowany w komentarzu Jona –

1

Miałem ten sam problem. Powinienem przeczytać wiadomość przed rozpoczęciem go. Potrzebowałem dodać konstruktora bez parametrów ...:-)

public MyClass() { 
    //stuff 
} 
Powiązane problemy