Créer un type générique avec une interface générique au moment de l'exécution

.net c# expression-trees generics linq

Question

Je travaille sur un problème depuis quelques heures maintenant et je pense que je suis proche. Je travaille sur une application où nous pourrions avoir 50 à 100 types qui fonctionnent de la même manière. Donc au lieu de créer 50-100 classes, j'ai essayé de le rendre générique et voici ce que j'ai:

C'est la classe de base:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

Et voici l'interface:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

Et voici comment je l'utilise:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

Je suis coincé sur cette ligne d'en haut:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

Voici ma question:
Comment puis-je utiliser cela comme RavenWriterBase ou IRavenWriter? Quelque chose comme:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

Je pense que cela doit être quelque chose comme ça, mais je dois spécifier un type pour IRavenWriter <> et je ne le connais pas encore:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

Si je survole ravenWriter, mon objet me parvient:

entrez la description de l'image ici

Mais maintenant, je dois pouvoir l'utiliser de manière générique. Comment puis je faire ça?

Mettre à jour:

Je viens de penser à utiliser le mot clé dynamique, et cela fonctionne:

public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity

J'ai triché un peu parce que je me suis rendu compte que le Func était le même pour chaque IDataEntity, il n'était donc pas nécessaire de passer en paramètre à Initialize (). Cependant, au moins maintenant je peux appeler Initialize (). Mais maintenant que le Func est le même, je n’aurais plus besoin de l’interface générique.

Réponse acceptée

Ma solution serait de:

  • Créer une interface non générique d' IRavenWriter
  • Faire en IRavenWriter<T> hérite de IRavenWriter
  • Conserver Execute et ExecutionIntervalInSeconds dans IRavenWriter
  • Assurez- IRavenWriter avoir Func<DateTime> et l'utiliser dans votre écrivain
  • Déplacer l' Initialize vers IRavenWriter<T>
  • Utilisez une fabrique pour initialiser le Func en fonction du type et de l'expression:

Par exemple:

public class MyDateTime
{
    public DateTime This { get; set; }
}

public static Func<DateTime> GetFunk<T>(Expression<Func<T, DateTime>> timeOrderByFunc, T t)
{
    return () => timeOrderByFunc.Compile()(t);
}

Et vous utilisez:

public class MyDateTime
{
    public DateTime This { get; set; }
}

public static Func<DateTime> GetFunk<T>(Expression<Func<T, DateTime>> timeOrderByFunc, T t)
{
    return () => timeOrderByFunc.Compile()(t);
}

Réponse populaire

Il n’est pas difficile de transformer Type exécution en paramètre Type générique au moment de la compilation. Introduisez simplement une nouvelle interface pour créer / initialiser vos objets:


interface IRawenWriterFactory
{
  object Create();
}

class RawenWriterFactory<T> : IRawenWriterFactory
{
  public object Create()
  {
    Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime;

    var ravenWriter = new RavenWriterBase<T>();
    ravenWriter.Initialize(60, func);

    return ravenWriter;
  }
}

Créez maintenant RawenWriterFactory avec dataEntityType comme vous avez créé ravenWriter et utilisez-le via une interface non générique IRavenWriterFactory.

Cependant, il pourrait y avoir des solutions plus simples si vous modifiez votre conception Par exemple, si vous transformez la méthode Initialize en constructeur, vous pourrez passer func comme paramètre Activator.CreateInstance et vous n’auriez pas besoin d’une interface générique pour l’initialisation.




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