类映射错误: ‘ T’必须是具有公共无参数构造函数的非抽象类型

当映射类我得到错误‘ T’必须是一个非抽象类型与一个公共的无参数构造函数,以使用它作为参数‘ T’在泛型类型或方法。

下面是我的 SqlReader 基类

 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
}

我要做的是,执行一些命令并动态填充类。课程安排如下:

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 Class 的类,它使用以下方法:

 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 是 Restaurant 也有一个无参数的公共构造函数。

78180 次浏览

The problem is that you're trying to use the T from SqlReaderBase as the type argument for MapperBase - but you don't have any constraints on that T.

Try changing your SqlReaderBase declaration to this:

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

Here's a shorter example which demonstrates the same issue:

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


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

The fix is to change Foo<T>'s declaration to:

class Foo<T> where T : new()

Then the compiler will know that the T from Foo is a valid type argument for Bar.

The constraints must apply to every type in the chain; hence you need:

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

Without this, you can't satisfy the constraint for T in:

protected abstract MapperBase<T> GetMapper();

or

MapperBase<T> mapper = GetMapper();

since MapperBase<> is only usable when T has : new()

I had the same issue. I should have read the message before Googling it. I needed to add a parameterless constructor ... :-)

public MyClass() {
//stuff
}