Beim Mappen der Klasse erhalte ich den Fehler, dass 'T' ein nicht abstrakter Typ mit einem öffentlichen parameterlosen Konstruktor sein muss, um ihn als Parameter 'T' im generischen Typ oder der generischen Methode zu verwenden.
Unten ist meine SqlReaderBase-Klasse
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
}
Was ich versuche, ist, ich führe einen Befehl aus und fülle meine Klasse dynamisch aus. Die Klasse ist unten angegeben:
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() { }
}
}
Um meine Klasseneigenschaften dynamisch zu füllen, habe ich eine andere Klasse namens MapperBase Class mit folgenden Methoden:
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;
}
}
Es gibt eine andere Klasse, die die SqlreaderBaseClass mit dem Namen DefaultSearch erbt. Code ist unten
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;
}
}
Aber wann immer ich versuchte zu erstellen, erhalte ich den Fehler "T" muss ein nicht abstrakter Typ mit einem öffentlichen parameterlosen Konstruktor sein, um ihn als Parameter "T" im generischen Typ oder in der generischen Methode zu verwenden. Sogar T here is Restaurant hat einen Parameterless Public-Konstruktor.
Das Problem ist, dass Sie versuchen, T
von SqlReaderBase
als Typargument für MapperBase
zu verwenden - aber Sie haben keine Einschränkungen für das)T
.
Versuchen Sie, Ihre SqlReaderBase
-Deklaration folgendermaßen zu ändern:
public abstract class SqlReaderBase<T> : ConnectionProvider
where T : new()
Hier ist ein kürzeres Beispiel, das dasselbe Problem demonstriert:
class Foo<T>
{
Bar<T> bar;
}
class Bar<T> where T : new()
{
}
Das Update besteht darin, die Deklaration von Foo<T>
Zu ändern:
class Foo<T> where T : new()
Dann weiß der Compiler, dass T
von Foo
ein gültiges Typargument für Bar
ist.
Die Einschränkungen müssen für jeden Typ in der Kette gelten. daher brauchst du:
public abstract class SqlReaderBase<T> : ConnectionProvider where T : new()
Ohne dies können Sie die Bedingung für T
nicht erfüllen in:
protected abstract MapperBase<T> GetMapper();
oder
MapperBase<T> mapper = GetMapper();
da MapperBase<>
nur verwendbar ist, wenn T
: new()
hat
Ich hatte das gleiche Problem. Ich hätte die Nachricht lesen sollen, bevor ich sie google. Ich musste einen parameterlosen Konstruktor hinzufügen ... :-)
public MyClass() {
//stuff
}