web-dev-qa-db-ja.com

クラスマッピングエラー:「T」は、パブリックパラメータレスコンストラクターを持つ非抽象型でなければなりません

クラスをマッピングしている間、ジェネリック型またはメソッドでパラメーター '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;
        }

    }

DefaultSearchと呼ばれるSqlreaderBaseClassを継承する別のクラスがあります。コードは以下です

 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でさえ、レストランにはパラメーターレスのパブリックコンストラクターがあります。

64
user240141

問題は、Tの型引数としてSqlReaderBaseからの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()

コンパイラは、TからのFooBarの有効な型引数であることを認識します。

114
Jon Skeet

制約は、チェーン内のすべてのタイプに適用する必要があります。したがって、あなたが必要です:

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

これがないと、Tの制約を満たすことができません。

_protected abstract MapperBase<T> GetMapper();
_

または

_MapperBase<T> mapper = GetMapper();
_

_MapperBase<>_はのみT: new()がある場合に使用できるため

12
Marc Gravell

同じ問題がありました。グーグルする前にメッセージを読むべきだった。パラメータなしのコンストラクタを追加する必要がありました... :-)

public MyClass() {
  //stuff
}
3
Yohan Dahmani