2015-12-23 1 views
10

Je souhaite ajouter une interface à certains types prédéfinis. J'ai une interface, IConcludable, que j'utilise comme contrainte pour Conclusion<T>. Je n'ai aucune idée de comment aborder cela, ou si c'est même possible.Existe-t-il un moyen d'étendre un type intégré pour hériter d'une interface?

Mise en page de base

public interface IConcludable { } 

public struct Conclusion<T> where T : IConcludable 
{ 
    public bool IsSuccessful; 
    public T Result; 

    // Constructors, members, etc. 
} 

public class ErrorReport : IConcludable { ... } 

public class MathArg : IConcludable { ... } 

public class ParseResult : IConcludable { ... } 

de mise en œuvre

public Conclusion<ParseResult> ParseInput (string input) 
{ 
    // Parse input... 
    // Initialize ParseResult object... 

    return new Conclusion<ParseResult>(result); 
} 

Problème

Quand je reçois la valeur finale, il est un type intégré comme int, double, string, bool, etc. Je voudrais utiliser Conclusion<T> comme un retour parce que j'ai une classe qui gère les rapports d'erreur lorsque la chaîne d'entrée est invalide:

if (conclusion.ReturnObject is ErrorReport) 
{ 
    ErrorManager errorManager = new ErrorManager(); 
    errorManager.Resolve(conclusion); 
} 

recherche

j'ai regardé contraintes.

Il semble que les contraintes ne font qu'ajouter ensemble, donc y compris les interfaces de chaque type intégré que j'ai besoin, il faudrait définir une montagne de méthodes qui n'ont rien à voir avec mon Conclusion struct.


Méthodes d'extension

Ces facteurs modifient réellement le comportement des types intégrés. Ce n'est pas ce que je cherche car mon interface, IConcludable, n'a pas de méthodes.

Remplacement types intégrés

pas possible. Je n'ai pas besoin de changer le comportement de ces types. Je veux juste ajouter une interface vide.

Il ne semble rien y avoir à ajouter une interface à un type intégré. Je ne suis pas sûr si "Héritage" est ce à quoi il serait fait référence. Est-ce possible?

Modifier

Une meilleure explication de struct Conclusion

J'utilise la struct conclusion comme un objet de retour dans la plupart de mes méthodes. C'est parce que j'utilise des délégués. Voir le code actuel des objets ci-dessous:

public delegate Conclusion<T> Validator<T>(T subclass) where T : IVerifiable<T>; 

public delegate Conclusion<BaseFunction> Executor(BaseFunction subclass); 

public struct Conclusion<T> where T : IConcludable 
{ 
    public bool IsSuccessful; 
    public T ReturnObject; 

    public Conclusion(T returnObject) 
    { 
     this.ReturnObject = returnObject; 
     this.IsSuccessful = returnObject is Error ? false : true; 
    } 
} 

public class BaseFunction : IVerifiable<BaseFunction>, IConcludable 
{ 
    public List<BaseArgument> Args; 
    public Executor Executing; 
    public Validator<BaseFunction> Validating; 
    public string UserInput; 

    public Conclusion<BaseFunction> Validate(BaseFunction subclass) 
    { 
     if (this.Validating != null) 
     { 
      return Validating(subclass); 
     } 
     else 
     { 
      StringBuilder message = new StringBuilder(); 
      message.Append("A Validating delegate has not been assigned."); 

      throw new InvalidOperationException(message.ToString()); 
     } 
    } 

    public Conclusion<BaseFunction> Execute(BaseFunction subclass) 
    { 
     if (this.Executing != null) 
     { 
      return this.Executing(subclass); 
     } 
     else 
     { 
      StringBuilder message = new StringBuilder(); 
      message.Append("An Executing delegate has not been assigned."); 

      throw new InvalidOperationException(message.ToString()); 
     } 
    } 
} 

public class Function<T> : BaseFunction 
{ 
    public T Result; 

    public Function() 
    { 
     base.Args = new List<BaseArgument>(); 
    } 
} 

public class BaseArgument : IVerifiable<BaseArgument>, IConcludable 
{ 
    public string Role; 
    public string UserInput; 
    public int Position; 
    public Validator<BaseArgument> Validating; 

    public Conclusion<BaseArgument> Validate(BaseArgument subclass) 
    { 
     if (this.Validating != null) 
     { 
      return Validating(subclass); 
     } 
     else 
      throw new InvalidOperationException(); 
    } 
} 

public class Argument<T> : BaseArgument 
{ 
    public T Value; 

    public Argument(int position) 
    { 
     base.Position = position; 
    } 
} 

public static class ExecutionHandler 
{ 
    public static Conclusion<BaseFunction> Sum(BaseFunction subclass) 
    { 
     subclass = (Function<double>)subclass; 

     // Execution code. 

     return new Conclusion<BaseFunction>(subclass); 
    } 

    public static Conclusion<BaseFunction> Concatenate(BaseFunction subclass) 
    { 
     subclass = (Function<double>)subclass; 

     // Execution code. 

     return new Conclusion<BaseFunction>(subclass); 
    } 
} 

Si j'ai besoin de poster plus, je le ferai. mais c'est vraiment beaucoup à regarder. Le type de retour des méthodes assignées par tous les délégués que j'utilise a un type de retour de Conclusion<T> afin que je puisse avoir un objet de retour ainsi qu'une erreur s'il y en a une. Les fonctions dans le code ci-dessus renvoient Conclusion<BaseFunction>, mais ce retour est converti en un objet Addend<T> s'il s'agit d'un nombre. S'il fait partie d'un autre type de fonction qui renvoie un ou un bool ou un autre type, il est converti en un type de classe différent. À la fin d'un calcul numérique, le retour sera quelque chose comme Conclusion<int> ou Conclusion<double>. Donc, ajouter int et double à l'interface IConcludable est ce que j'essaie de faire.

Une meilleure explication de l'application

Je vous écris une application console C#. Il prend l'entrée de l'utilisateur, et écrit une réponse. L'entrée est similaire aux formules Excel: Sum(5, 15, Average(2, 3), 5) ou Concatenate("5 + 5 = ", Text(Sum(5, 5))). La chaîne d'entrée est validée, analysée et renvoie un résultat.

+0

comme je le vois dans votre implémentation, vous retournez Conclusion . Mais vous avez aussi dit *** Quand j'obtiens la valeur finale, c'est un type intégré comme int, double, string, bool, etc ***, je ne comprends pas cette partie. –

+0

Bien que votre question soit très bien posée, je pense que vous devriez affûter la * question * que vous avez, car actuellement ce n'est pas clair ce qui ne fonctionne pas avec cette construction. –

+1

N'est-ce pas un scénario pour ** Modèle d'adaptateur **? –

Répondre

1

MISE À JOUR (ADD PLUS EXPLICATION)

Comme l'a demandé, je veux expliquer un peu plus sur ma dernière réponse.

Exigences

  • La Conclusion nécessité de soutenir les deux types valeur et le type référence
  • Générique
  • Types de valeur: tous les types de données numériques (int, court, long, etc.), boolean, char, date ....
  • Types de référence: chaîne et classe définie par l'utilisateur (dans l'exemple OP, IConcludable)

Solution:

  • introduisons une classe de base (AbstractConclusion) qui accepte Object comme entrée générique
  • Déplacer la logique à la classe de base pour la réutilisation
  • introduisent deux nouvelles implémentations concrètes qui accepte struct et IConcluable (avoir la possibilité d'ajouter plus d'implémentation, par exemple: string)
  • Les classes héritées sont capables de toutes les méthodes de la classe de base

RÉPONSE ORIGINAL:

Vous pouvez mettre la logique dans AbstractConclusion classe, et ont deux implémentations de celui-ci (Conclusion qui accepte IConcludeable et PrimitiveConclusion qui accepte le type de données struct)

Voir exemple de code ci-dessous:

void Main() 
{ 
    PrimitiveConclusion<int> primitiveConclusion = new PrimitiveConclusion<int>(1); 
    Conclusion<ParseResult> parseResultConclusion = new Conclusion<ParseResult>(new ParseResult {}); 

    Console.WriteLine($"{primitiveConclusion.Result.GetType()}"); 
    Console.WriteLine($"{parseResultConclusion.Result.GetType()}"); 
} 

public class TestClass 
{ 
    public Conclusion<ParseResult> ParseInput(string input) 
    { 
     return new Conclusion<ParseResult>(null); 
    } 
} 

public interface IConcludable { } 

public abstract class AbstractConclusion<T> 
{ 
    public AbstractConclusion(T t) 
    { 
     IsSuccessful = t != null; 
     Result = t; 
    } 
    public bool IsSuccessful; 
    public T Result; 
} 

public class Conclusion<T> : AbstractConclusion<T> where T : IConcludable 
{ 
    public Conclusion(T t) : base(t) 
    { 
    } 
} 


public class PrimitiveConclusion<T> : AbstractConclusion<T> where T : struct 
{ 
    public PrimitiveConclusion(T t) : base(t) 
    { 
    } 
} 


public class ParseResult : IConcludable { } 
+0

kienct89, j'essaie de comprendre ce que fait la classe abstraite. Il semble qu'il accepterait n'importe quelle valeur. Comme 'T' est équivalent à' object'. Est-ce que c'est ce que la classe abstraite est dans votre exemple? Merci. –

+0

@TylerPantuso: 'AbstractConclusion' est juste une classe de base pour regrouper toutes les fonctionnalités similaires de Conclusion, donc vous n'avez pas besoin de réécrire pour toutes les classes enfants. Pour la deuxième partie de votre question, il devrait accepter tous les types (afin de soutenir primitive, int et IConcluable). –

+0

"IConcludable" ne devrait-il pas être supprimé complètement? –

0

Avec la contrainte de type générique where T : IConcludable, vous ne pouvez pas passer int comme argument générique. Et aussi il n'y a aucun moyen d'ajouter une interface au type primitif.

Vous pouvez faire une solution pour contourner ce problème. Vous pouvez mettre la logique principale de Conclusion en classe abstraite de base et d'hériter de celui-ci, la restructuration Conclusion comme class (parce que struct s prend pas en charge l'héritage) et créer des classes

public class Conclusion<T> : BaseConclusion 
where T : IConcludable 

et

public class PrimitiveConclusion<T> : BaseConclusion 
where T : struct 

et vous devrait créer une autre classe pour string, comme string n'est pas struct et ne pas implémenter IConcludable

Comme je le sais, il y a s pas d'autre moyen de passer des types différents en tant qu'arguments génériques.


En outre, au lieu de créer Conclusion classe pour les types intégrés que vous pouvez créer struct wrapper, qui mettra en œuvre IConcludable. Et un accord avec elle

public struct Wrapper<T> : IConcludable 
{ 
    public T Value { get; set; } 
}