Errore di mapping di classi: “T” deve essere un tipo non astratto con un costruttore publicless pubblico

Mentre la class di mapping che sto ricevendo, l’errore “T” deve essere un tipo non astratto con un costruttore pubblico senza parametri per utilizzarlo come parametro “T” nel tipo o metodo generico.

Di seguito è la mia class SqlReaderBase

public abstract class SqlReaderBase : ConnectionProvider { #region Abstract Methods protected abstract string commandText { get; } protected abstract CommandType commandType { get; } protected abstract Collection GetParameters(IDbCommand command); **protected abstract MapperBase GetMapper();** #endregion #region Non Abstract Methods ///  /// Method to Execute Select Queries for Retrieveing List of Result ///  ///  public Collection ExecuteReader() { //Collection of Type on which Template is applied Collection collection = new Collection(); // 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 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 } 

Quello che sto cercando di fare è che eseguirò qualche comando e riempire dynamicmente la mia class. La class è data di seguito:

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

Per riempire dynamicmente le proprietà della mia class ho un’altra class chiamata class MapperBase con i seguenti metodi:

  public abstract class MapperBase 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 MapAll(IDataReader reader) { Collection collection = new Collection(); while (reader.Read()) { collection.Add(Map(reader)); } return collection; } } 

Esiste un’altra class che eredita lo SqlreaderBaseClass chiamato DefaultSearch. Il codice è sotto

  public class DefaultSearch: SqlReaderBase { protected override string commandText { get { return "Select Name from vw_Restaurants"; } } protected override CommandType commandType { get { return CommandType.Text; } } protected override Collection GetParameters(IDbCommand command) { Collection parameters = new Collection(); parameters.Clear(); return parameters; } protected override MapperBase GetMapper() { MapperBase mapper = new RMapper(); return mapper; } } 

Ma ogni volta che ho provato a creare, sto ricevendo errore “T” deve essere un tipo non astratto con un costruttore pubblico senza parametri per utilizzarlo come parametro “T” nel tipo o metodo generico. Anche T qui è ristorante ha un costruttore pubblico senza parametri.

Il problema è che stai cercando di usare la T da SqlReaderBase come argomento di tipo per MapperBase – ma non hai alcun vincolo su quella T

Prova a cambiare la dichiarazione SqlReaderBase a questo:

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

Ecco un esempio più breve che dimostra lo stesso problema:

 class Foo { Bar bar; } class Bar where T : new() { } 

La correzione è di cambiare la dichiarazione di Foo a:

 class Foo where T : new() 

Quindi il compilatore saprà che T da Foo è un argomento di tipo valido per Bar .

I vincoli devono essere applicati a tutti i tipi della catena; quindi hai bisogno di:

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

Senza questo, non è ansible soddisfare il vincolo per T in:

 protected abstract MapperBase GetMapper(); 

o

 MapperBase mapper = GetMapper(); 

poiché MapperBase<> è utilizzabile solo quando T ha : new()

Ho avuto lo stesso problema. Avrei dovuto leggere il messaggio prima di cercarlo su Google. Avevo bisogno di aggiungere un costruttore senza parametri … 🙂

 public MyClass() { //stuff }