简体   繁体   中英

Generic Class Loader: 'T' must be a non-abstract type with a public parameterless constructor

I have many similar classes and I am trying to create a generic method that loads a list of objects of each class. I am not using any ORM, but just loading a SqlDataReader with the respective SQL Query.

I have tried using an interface and using generics.

I have simplified the problem below using only 2 short classes:

Interface:

public interface IMyEntity<T> where T : new()
{
    public List<T> ConvertToObjects(SqlDataReader dr);

    public static IMyEntity<T> CreateInstance() 
    {
        return null;
    }
}

Class 1:

public class Cat : IMyEntity<Cat>
{   
    public long CatID { get; set; } 
    public string CatName { get; set; } 
    public int OwnerID { get; set; }

    public List<Cat> ConvertToObjects(SqlDataReader dr)
    {
        List<Cat> cats = new();
        if (dr.HasRows)
        {
            while (dr.Read())
            {
                Cat cat = new()
                {
                    CatID = dr.GetInt32("CatID"),
                    CatName = dr.GetString("CatName"),
                    OwnerID = dr.GetInt32("OwnerID")
                };
                cats.Add(cat);
            }
            dr.Close();
        }
        return cats;
    }

    public IMyEntity<Cat> CreateInstance()
    {
        IMyEntity<Cat> cat = new Cat();
        return cat;
    }
}

Class 2:

public class Dog : IMyEntity<Dog>
{
    public long DogID { get; set; }
    public string DogName { get; set; }
    public int Age { get; set; }

    public List<Dog> ConvertToObjects(SqlDataReader dr)
    {
        List<Dog> dogs = new();
        if (dr.HasRows)
        {
            while (dr.Read())
            {
                Dog dog = new()
                {
                    DogID = dr.GetInt32("DogID"),
                    DogName = dr.GetString("DogName"),
                    OwnerID = dr.GetInt32("Age")
                };
                dogs.Add(dog);
            }
            dr.Close();
        }
        return dogs;
    }

    public IMyEntity<Dog> CreateInstance()
    {
        IMyEntity<Dog> dog = new Dog();
        return dog;
    }
}

And I have another class with this method:

public async Task<IEnumerable<T>> GetObjectAsync<T>(string procedureName)
{
    if (_connection.State != ConnectionState.Open) _connection.Open();
    SqlCommand command = new(procedureName, _connection);
    SqlDataReader dr = await cmd.ExecuteReaderAsync().ConfigureAwait(false);

    var myEntity = IMyEntity<T>.CreateInstance();
    IEnumerable<T> objs = myEntity.ConvertToObjects(dr);

    return objs;
}

The line with 'CreateInstance' is returning the following error: "'T' must be a non-abstract type with a public parameterless constructor in order to use it as parameter 'T' in the generic type or method 'IMyEntity'"

The T: new() constraint is missing in the calling method's own generic type.

public async Task<IEnumerable<T>> GetObjectAsync<T>(string procedureName)

Thus the compiler cannot guarantee the constraint requirement for the interface in IMyEntity<T> is met. It is not related to any specific method call and the restriction requirement comes from the interface definition itself.

public interface IMyEntity<T> where T : new()

Either remove the restriction from the interface — in which case new T() cannot be used — or add the restriction to the calling method's generic type.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM