mardi 27 février 2018

Can I use reflection to provide type arguments to a generic repository?

Goal

I would like to be able to count the number of times a specific PrimaryImageId is used within a number of different db entities.

Their classes each have a PrimaryImageId property and are adorned with a [HasPrimaryImage] attribute.

I may not know these classes in advance, so I want to use the [HasPrimaryImage] attribute to identify them, not hard code in the types.

I've Tried

I am using a generic repository method. But although it works when called with 'hard-coded' types:

GetCount<NewsItem>(x => x.PrimaryImageId == id);

...I can't get it to work when the type argument is provided from reflection.

var types = GetTypesWithHasPrimaryImageAttribute();
foreach(Type t in types)
{
    GetCount<t>(x => x.PrimaryImageId == id);
}

I've tried calling GetCount<t>(), GetCount<typeof(t)> and a few other silly things.

It appears that I can't call a generic method using a reflection generated type.

Question

Jon Skeet recommends using MakeGenericMethod in his answer, but I'm struggling to do that and wondering if that is overkill for my requirements. Is there an easier / better way to achieve what I'm after?



Db Entity Classes

[HasPrimaryImage]
public class NewsItem 
{
    public int PrimaryImageId { get; set; }

    // .. other properties
}


[HasPrimaryImage]
public class Product 
{
    public int PrimaryImageId { get; set; }

    // .. other properties
}

Generic Repository Method

public virtual int GetCount<TDataModel>(Expression<Func<TDataModel, bool>> wherePredicate = null)
    where TDataModel : class, IDataModel
{
    return GetQueryable<TDataModel>(wherePredicate).Count();
}

Get All Classes with HasPrimaryImage Attribute:

public static IEnumerable<Type> GetTypesWithHasPrimaryImageAttribute()
{
    var currentAssembly = Assembly.GetExecutingAssembly();
    foreach (Type type in currentAssembly.GetTypes())
    {
        if (type.GetCustomAttributes(typeof(HasPrimaryImageAttribute), true).Length > 0)
        {
            yield return type;
        }
    }
}   





Aucun commentaire:

Enregistrer un commentaire