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


74

在映射类我遇到错误“ T”的同时,它必须是具有公共无参数构造函数的非抽象类型,才能在通用类型或方法中将其用作参数“ T”。

以下是我的SqlReaderBase类

 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类的类:

 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餐厅都具有无参数公共构造函数。

Answers:


135

问题是,你试图使用TSqlReaderBase作为类型参数MapperBase-但你没有任何的约束 T

尝试将SqlReaderBase声明更改为此:

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

这是一个较短的示例,它演示了相同的问题:

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

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

解决方法是将Foo<T>的声明更改为:

class Foo<T> where T : new()

然后,编译器将知道TfromFoo是的有效类型参数Bar


谢谢它的工作。但是还有另一件事,无需创建受保护的抽象Mapperbase <T>,就可以在SqlReaderBase本身中调用MapperBase <T>。方法。

1
@Amit:您可以具有约束的单独类型参数TMapperwhere TMapper : MapperBase<T>, new()
Jon Skeet 2010年

请提供实际的声明。.这将是gr8帮助

公共抽象类SqlReaderBase <T>:ConnectionProvider,其中TMapper:MapperBase <T>,T:new()是您要说的吗???

1
@AmitRanjan,如果您将鼠标悬停在红色波浪上会显示什么意思?(或者也许在编译器输出中)
Marc Gravell

13

约束必须适用于链中的每种类型。因此,您需要:

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

没有这个,您将无法满足Tin的约束:

protected abstract MapperBase<T> GetMapper();

要么

MapperBase<T> mapper = GetMapper();

因为MapperBase<>当可用T具有: new()


你们的解决方案奏效了。但是还有一个问题,发布在Jon的评论中

4

我遇到过同样的问题。在谷歌搜索之前,我应该已经阅读了该消息。我需要添加一个无参数的构造函数... :-)

public MyClass() {
  //stuff
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.