1. ホーム
  2. c#

[解決済み] クラスマッピングエラー: 'T' はパブリックパラメータレスコンストラクタを持つ非抽象型である必要があります。

2023-06-20 08:39:08

質問

クラスをマッピングする際に、'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はRestaurantでもパラメータレスのPublicコンストラクタを持っています。

どのように解決するのですか?

問題なのは、あなたが使っている 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 から Foo の有効な型引数です。 Bar .