2010-06-16 12 views
45

Lors de la mise en correspondance de la classe, l'erreur 'T' doit être un type non abstrait avec un constructeur public sans paramètre afin de l'utiliser comme le paramètre 'T' dans le type ou la méthode générique.Erreur de mappage de classe: 'T' doit être un type non abstrait avec un constructeur public sans paramètre

Ci-dessous mon SqlReaderBase classe

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 
    } 

Ce que je suis en train de faire est, je suis executine une commande et remplir dynamiquement ma classe. La classe est donnée ci-dessous:

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

    } 
} 

Pour remplir mes propriétés de classe que j'ai dynamiquement une autre classe appelée MapperBase classe avec des méthodes suivantes:

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

    } 

Il y a une autre classe qui hérite du SqlreaderBaseClass appelé DefaultSearch. Le code est ci-dessous

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

Mais chaque fois que j'essayé de construire, je reçois l'erreur « T » doit être un type non abstrait avec un constructeur parameterless public afin de l'utiliser comme paramètre « T » dans le type générique ou méthode. Même ici, le restaurant a un constructeur Public Parameterless.

Répondre

85

Le problème est que vous essayez d'utiliser le T de SqlReaderBase comme argument de type pour MapperBase - mais vous n'avez pas de contraintes sur queT.

Essayez de changer votre déclaration SqlReaderBase à ceci:

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

Voici un exemple plus court qui démontre la même question:

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

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

La solution est de changer la déclaration de Foo<T> à:

class Foo<T> where T : new() 

Ensuite, le compilateur saura que le T de Foo est un argument de type valide pour Bar.

+0

Merci cela a fonctionné. Mais encore une chose est-il un moyen d'appeler MapperBase dans SqlReaderBase lui-même sans créer Protected Abstract Mapperbase GetMapper(); méthode. –

+1

@Amit: Vous pourriez avoir un paramètre de type * séparé * TMapper' avec une contrainte: 'où TMapper: MapperBase , new()' –

+0

s'il vous plaît fournissez-moi la déclaration réelle .. ce serait une aide gr8 –

9

Les contraintes doivent s'appliquer à tous les types de la chaîne; donc vous avez besoin:

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

Sans cela, vous ne pouvez pas satisfaire la contrainte pour T dans:

protected abstract MapperBase<T> GetMapper(); 

ou

MapperBase<T> mapper = GetMapper(); 

depuis MapperBase<> est que utilisable lorsque T a : new()

+0

Guys votre solution a fonctionné. Mais encore un autre numéro, posté dans le commentaire de Jon –

1

J'ai eu le même problème. J'aurais dû lire le message avant de le googler. J'avais besoin d'ajouter un constructeur sans paramètre ...:-)

public MyClass() { 
    //stuff 
} 
Questions connexes