Création dynamique de type à l'exécution pour dapper querymultiple Méthode de lecture utilisant Reflection

dapper reflection types

Question

J'essaie de passer le type de classe dynamiquement à l'exécution. Le code ci-dessous donne une erreur à la section de code:

    object newObject Activator.CreateInstance(Type.GetType(t.GetGenericArguments()[0].FullName));
    data.Read<newObject>();

J'ai aussi essayé

    data.Read<Type.GetType(t.GetGenericArguments()[0].FullName)>();  

Voici la méthode complète:

    public object FetchMultipleRecordSet(string storedProcedure, IList<QueryParameter> parameterCollection, object dataList)
    {
        if (!string.IsNullOrEmpty(storedProcedure))
        {
            using (SqlConnection sql = CreateDatabaseConnection())
            {
                DynamicParameters dynamicParameter = ConvertToDynamicParameters(parameterCollection);
                var data = sql.QueryMultiple(storedProcedure, dynamicParameter, null, null, commandType: CommandType.StoredProcedure);

                PropertyInfo[] properties = dataList.GetType().GetProperties();
                foreach (PropertyInfo property in properties)
                {
                    Type t = property.PropertyType;
                    if (t.BaseType == null && t.IsGenericType && t.Namespace == "System.Collection.Generic")
                    {
                        //property.SetValue(data.Read());
                        object newObject = Activator.CreateInstance(Type.GetType(t.GetGenericArguments()[0].FullName));
                        data.Read<>();    
                    }
                    else if (t.Namespace != "System")
                    {
                        //typeCollection.Add(Type.GetType(t.FullName));
                    }
                }
            }
        }

        return dataList;
    }

Voici le modèle de vue que je veux utiliser:

    public class ResultCollection
    {
        public IList<ShortCodeList> ShortCodeListCollection { get; set; }
        public DateTime CurrentDate { get; set; }
        public UserMembershipPlan UserMembershipPlanRecord { get; set; }
        public IList<EmailRecipients> EmailRecipientsCollection { get; set; }
    }

Je dois passer le type dans data.Read () afin que la propriété qui se trouve sous forme générique puisse être associée au jeu de résultats. Si je passe "newObject" ou "Type.GetType (t.GetGenericArguments () [0] .FullName)", cela me donne toujours une erreur. Cela peut paraître maladroit mais je pense que ça devrait marcher.

Réponse d'expert

Pour le moment, l'API typée pour dapper utilise des génériques. Il existe une API non typée mais vous devez effectuer votre propre mappage de membre. Pour appeler une méthode générique via un type, vous devez utiliser MethodInfo sur la méthode générique, MakeGenericMethod et Invoke. Il y a aussi un moyen de le falsifier avec la dynamic , en ajoutant une méthode shim dans votre code, semblable à:

dynamic template = ...  // activator etc
Evil(template, otherArgs...);

Evil<T>(T template, otherArgs...) {
    use some <T> method etc here
}

Comme exemple plus complet, les travaux suivants:

public void TypeBasedViaDynamic()
{
    Type type = GetSomeType();

    dynamic template = Activator.CreateInstance(type);
    dynamic actual = CheetViaDynamic(template,
        "select @A as [A], @B as [B]", new { A = 123, B = "abc" });
    ((object)actual).GetType().IsEqualTo(type);
    int a = actual.A;
    string b = actual.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");
}

T CheetViaDynamic<T>(T template, string query, object args)
{
    return connection.Query<T>(query, args).SingleOrDefault();
}
static Type GetSomeType()
{
    return typeof(SomeType);
}
public class SomeType
{
    public int A { get;set; }
    public string B { get;set; }
}

Notez que cela commence uniquement par un Type et remplit une instance via une instance factice (via Activator ) et dynamic . Ce n'est pas beau, mais ça marche. Cependant, je viens juste de pousser quelques modifications sur dapper qui acceptent une instance de Type tant que paramètre, ce qui fait que les éléments suivants fonctionnent - sans avoir besoin de ces hacks:

public void TypeBasedViaType()
{
    Type type = GetSomeType();

    dynamic actual = connection.Query(type,
        "select @A as [A], @B as [B]", new { A = 123, B = "abc" }
        ).FirstOrDefault();
    ((object)actual).GetType().IsEqualTo(type);
    int a = actual.A;
    string b = actual.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");
}

Et les lecteurs multi-réseaux aussi:

public void TypeBasedViaTypeMulti()
{
    Type type = GetSomeType();

    dynamic first, second;
    using(var multi = connection.QueryMultiple(
        "select @A as [A], @B as [B]; select @C as [A], @D as [B]",
        new { A = 123, B = "abc", C = 456, D = "def" }))
    {
        first = multi.Read(type).Single();
        second = multi.Read(type).Single();
    }
    ((object)first).GetType().IsEqualTo(type);
    int a = first.A;
    string b = first.B;
    a.IsEqualTo(123);
    b.IsEqualTo("abc");

    ((object)second).GetType().IsEqualTo(type);
    a = second.A;
    b = second.B;
    a.IsEqualTo(456);
    b.IsEqualTo("def");
}

Notez que la dynamic dans ces nouveaux exemples d'API est purement pratique pour les tests; dynamic n’est pas une partie importante de l’approche.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi