2017-10-15 3 views
1

que j'ai une interface générique qui stocke une valeur qui est tapé par le paramètre générique:Plusieurs classes qui mettent en œuvre une interface générique dans un seul tableau

public interface IFoo<TValue> 
{ 
    TValue SomeValue { get; set; } 
} 

Puis j'ai deux classes, StringFoo et DoubleFoo dont SomeValues sont string s et double s respectivement:

public class StringFoo : IFoo<string> 
{ 
    string SomeValue { get; set; } 
} 

public class DoubleFoo : IFoo<double> 
{ 
    double SomeValue { get; set; } 
} 

je décide maintenant que je veux un tableau qui peut contenir les deux StringFoo s et DoubleFoo s:

var foos = IFoo<object>[] { 
    new StringFoo { SomeValue = "a value" }, 
    new DoubleFoo { SomeValue = 123456789 } 
} 

Je pense que, puisque les deux string et double sont sous-classes de object, ils seraient tous deux autorisés dans ce tableau. Cependant, je pensais mal.

Alors, j'ai essayé d'utiliser covariance:

public interface IFoo<out TValue> 

Mais, puisque l'interface contient les deux setters et getters, je ne peux pas le faire.

Donc, peut deux classes qui implémentent une interface générique dans un tableau?

+3

double possible de [C# - Plusieurs types génériques dans une liste] (https://stackoverflow.com/questions/353126/c-sharp-multiple-types-génériques-dans-une-liste) – Fruchtzwerg

+0

La liste et T [] sont des constructions complètement différentes qui peuvent évidemment être converties de l'une à l'autre mais peuvent afficher un comportement très différent en fonction de la future conception du langage. décisions et leur implémentation d'exécution sous-jacente. C'est pourquoi ces questions sont entièrement différentes. Fait que les réponses d'aujourd'hui sont similaires ou la même chose n'a pas d'importance du point de vue de la théorie de la langue. –

Répondre

1

Le problème peut être résolu de la manière dont la classe Bar est implémentée (mauvais exemple fourni). Le problème est que chaque fois que l'on essaie d'utiliser une interface générique ou une classe, l'implémentation d'un code d'interface générique peut compiler (fournir des distributions droites) mais le code lancera InvalidCastException pendant l'exécution.

public interface IFoo<TValue> 
{ 
    TValue SomeValue { get; set; } 
} 

public class StringFoo : IFoo<string> 
{ 
    public string SomeValue { get; set; } 
} 

public class DoubleFoo : IFoo<double> 
{ 
    public double SomeValue { get; set; } 
} 

public class Foo<TValue> : IFoo<TValue> 
{ 
    public TValue SomeValue { get; set; } 
} 

public abstract class Bar 
{ 

} 

public class Bar<TValue> : Bar, IFoo<TValue> 
{ 
    public TValue SomeValue { get; set; } 
} 

public static class Verify 
{ 
    public static void QuestionArray() 
    { 
     var foos = new IFoo<object>[] 
     { 
      (IFoo<object>) new StringFoo { SomeValue = "a value" }, 
      (IFoo<object>) new DoubleFoo { SomeValue = 123456789 } 
     }; 
    } 

    public static void BadAnswerArray() 
    { 
     var foo = new IFoo<object>[] 
     { 
      (IFoo<object>) new Foo<string>(), 
      new Foo<object>(), 
     }; 
    } 

    public static void GoodAnswer() 
    { 
     var foo = new Bar[] 
     { 
      new Bar<string>(), 
      new Bar<object>(), 
      new Bar<double>() 
     }; 
    } 
} 

Et pour vérifier la solution, on peut exécuter des tests où seul GoodAnswerTest passera:

public class GenericsInArrayTests 
{ 
    [Fact] 
    public void QuestionArrayTest() 
    { 
     Verify.QuestionArray(); 
    } 

    [Fact] 
    public void BadAnswerTest() 
    { 
     Verify.BadAnswerArray(); 
    } 

    [Fact] 
    public void GoodAnswerTest() 
    { 
     Verify.GoodAnswer(); 
    } 
} 
+0

S'il n'y a pas d'utilisation d'une classe abstraite, alors nous ne pouvons pas réellement l'utiliser ici. –

+0

@jacek Est-il possible de le faire sans le casting à 'IFoo '? Le code aurait l'air plus propre sans (et être plus court à écrire). – Zoweb

+0

@jacek De plus, quand j'essaie d'utiliser le casting, VS me dit "Cast suspect: il n'y a aucun type dans la solution qui est héritée de StringFoo et IFoo " * edit * Et je viens de réaliser que 'Bar' est pour non-casting ... Droit ... – Zoweb