2017-10-15 6 views
3

Je travaille à rendre EF plus facile à tester en écrivant quelques aides qui me feront des propriétés. J'ai deux ou trois champs soutenantActiver le type avec un type de retour générique

private Mock<DbSet<Workflow>> mockedWorkFlows; 
private Mock<DbSet<WorkflowError>> mockedWorkFlowErrors; 

Et je veux une fonction générique pour pouvoir me retourner le champ de support correct avec la fonction suivante

public Mock<DbSet<T>> Mocked<T>(T t) where T : class 
{ 
    if ((object)t is Workflow) 
    { 
     return mockedWorkFlows; //cannot Workflow to T 
    } 
} 

Il y a plusieurs champs d'appui privés que je veux être renvoyé en fonction du type passé.

Cependant, même si j'ajoute une contrainte de classe de Workflow, j'obtiens la même erreur.

J'ai également essayé d'activer le type t's mais pas de chance non plus. Les types des plusieurs champs de support ne partagent pas un ancêtre commun, autre que l'objet. Est ce que j'essaye de faire possible?

+0

Je ne vois pas ce que le point de cette méthode serait. Créer un simulacre prend 1 ligne de code et si vous voulez installer le simulacre vous devez configurer individuellement chaque maquette de toute façon, alors pourquoi ne pas créer simplement une usine pour certains types de mock. – FCin

+0

Il y a plus d'une ligne de code pour imiter un IDbSet de votre contexte EF. J'ai une interface fluide pour assigner les données, mais vous devez exposer le champ de sauvegarde quelque part parce que lorsque vous espionnez, c'est ce qui est réellement appelé. Je veux juste une API plus petite au lieu d'avoir un WorkflowsMocked, WorkflowErrorsMocked, etc. pour toutes les propriétés IDbSet du contexte. – wootscootinboogie

+0

Au lieu de se moquer de 'DbSet', avez-vous envisagé de vous moquer de' SqlConnection' à la place, par exemple, en utilisant le framework Effort? https://github.com/tamasflamich/effort –

Répondre

6

Si je comprends bien votre intention - vous pouvez le faire comme ceci:

// no need to pass instance of T - why? 
public Mock<DbSet<T>> Mocked<T>() where T : class 
{ 
    if (typeof(T) == typeof(Workflow)) { 
     // first cast to object, then to return type to avoid compile error 
     // compiler does not know mockedWorkFlows is Mock<DbSet<T>>, but you 
     // know it already, because you checked type 'T' 
     return (Mock<DbSet<T>>) (object) mockedWorkFlows; //cannot Workflow to T 
    } 
    // etc 
    return null; 
} 

Que ce soit une bonne idée est ou non une autre histoire.

+0

c'est ce que je cherchais. J'essayais d'utiliser le caractère lisse de l'interrupteur sur le type pour C# 7, mais c'est finalement ce que je cherchais (même si je reçois une erreur différente maintenant!) – wootscootinboogie

1

Il est possible d'abuser sérieusement C# 7 de switch pour obtenir ce que vous voulez en enclenchant une valeur sans rapport et en utilisant le motif var avec when gardes:

public Mock<DbSet<T>> Mocked<T>() where T : class 
{ 
    switch(true) 
    { 
     case var _ when typeof(T) == typeof(Workflow): 
      return ... 
     case var _ when typeof(T) == typeof(WorkflowError): 
      return ... 
     default: 
      return null; 
    } 
} 

Mais il est un code vraiment horrible, donc s'il vous plaît don Fais pas ça!

La possibilité de faire correspondre les types dans les instructions switch est une requête très courante. Il y a des propositions d'améliorations à C# sur le dépôt de langue officielle sur github (voir Proposal: switch on System.Type et p Proposal: Pattern match via generic constraint). Au fur et à mesure que d'autres fonctionnalités de correspondance de modèles sont ajoutées à C# (currently, set for "a 7.X release"), nous pouvons obtenir une syntaxe plus agréable pour cette fonctionnalité.