10
votes

Classe Delphes de en C #

Je sais que cette question a été posée auparavant, mais je n'ai pas encore trouvé une réponse courte et claire, alors j'espère qu'ils ne supprimeront pas cette question et je vais maintenant avoir une réponse claire:

Je suis travaillant actuellement en C # 5.0; .NET 4.5; Vs 2012. Je suis surtout un gars Delphi, même si j'ai terminé beaucoup avec C #. P>

à Delphi J'ai écrit des centaines d'usines de classe qui utilisent le type de conception suivant (très simplifié ici): P >

unit uFactory;

interface


type

    TClassofMyClass = class of TMyClass;
    TFactoryDict = TDictionary<TMyEnum, TClassofMyClass>;

var fDict:TFactoryDict;

implementation  

procedure initDict;
begin

    fDict:=TFactoryDict.create;
    fDict.add(myEnum1, TMyClass1);
    fDict.add(myEnum2, TMyClass2);
    fDict.add(myEnum3, TMyClass3);

end;


function Factory(const aEnum: TMyEnum): TMyClass;

var

    ClassofMyClass: TClassofMyClass;

begin

    if fDict.TryGetValue(aEnum, ClassofMyClass) then

    result := ClassofMyClass.Create(aParam);

end;

end.


3 commentaires

Les sous-classes TmyClass1 et TmyClass2 de TmyClass sont-elles?


@Martheen oui, cela est appliqué par la classe de TmyClass


Est-ce toujours manquant de c #?


4 Réponses :


1
votes

Si je vous ai bien compris, vous voulez avoir une référence à une classe statique. Ce n'est pas possible en C #.

Un seul exemple de la mise en œuvre de la méthode d'usine: http://www.codeproject.com/tips/328826/Implementaling --Factory-méthode-in-csharp


1 commentaires

La «classe de» à Delphi est une métaclasse - un type qui peut représenter génériquement tous les descendants de cette classe de base et fonctionne avec le polymorphisme en fonction de la classe descendante représentée. Rien à voir avec des classes statiques.



1
votes

La langue C # ne prend pas en charge les classes méta.

Vous devrez donc mettre en œuvre votre usine d'une autre manière. Une solution consiste à utiliser une instruction de commutation sur un énorme: xxx

Une autre option couramment utilisée consiste à le faire avec réflexion qui vous permettrait d'écrire du code plus proche de ce que vous êtes utilisé. faire.

et une autre option est de remplacer votre dictionnaire de classes avec un dictionnaire de délégués qui renvoient une nouvelle instance de votre objet. Avec la syntaxe Lambda que l'option donne un code très propre.

L'inconvénient de la réflexion est que vous abandonnez la sécurité de type temporel. Donc, tandis que l'approche fondée sur la réflexion est probablement la plus proche du code Delphi dans la question, ce n'est pas la voie que je choisirais personnellement.

plutôt que d'essayer de chaussure votre solution Delphi dans une langue qui ne veut pas Cette approche, je vous suggère de rechercher la solution C # idiomatique C #. Commencez par une recherche sur le Web pour une usine de classe.


11 commentaires

+1 - Merci. Oui, je sais à propos de Switch {Case:} - Delphi a également cela pour Enums, comme vous le savez bien. «Commencez par une recherche sur le Web pour la classe usine '- merci encore. Maintenant, avec tout le respect due, veuillez lire ma question à nouveau. :-)


Je pense avoir compris la question. Je voulais dire que vous trouverez une variété d'exemples d'usines C # sur le Web. Regardez-les et choisissez l'approche que vous aimez le mieux.


+1 L'OP a dit: "En espérant que je vais maintenant avoir une réponse claire" - cela ne signifie pas une recherche sur le Web. C'est pourquoi l'OP a libéré la question de cette façon. :-)


Vous avez la réponse claire. Une simple déclaration qu'il n'y a pas d'équivalent à la classe de. J'ai décrit trois moyens possibles pour mettre en œuvre une usine. Je pense que certaines recherches sur le Web donneront plus d'idées. Vous avez probablement déjà fait cela déjà et je veux juste savoir si vous pouvez le faire avec des classes méta. Eh bien, pas tout à fait. Les classes les plus proches des méta sont d'utiliser la réflexion.


David, vous obtenez toujours +1 de moi pour un dévouement pure et une connaissance encyclopédique. Mais...


Mais quoi? Je dis simplement qu'il y a des tas de façons de faire des usines. Il est difficile de le recommander un. Vous devez faire votre choix personnel. Et utiliser une recherche sur le Web vous donnera des idées supplémentaires au-delà de ce qui est ici. Quel est le mal? Bien que je ne puisse personnellement penser à aucune idée au-delà de ceux que j'ai décrits, mais je parie qu'il y en a quelques-unes!


Mais ....: Je cherche une réponse claire et discrète - la solution la plus propre, la plus simple la plus simple, la plus proche de l'approche Delphes, qui, comme je sache, vous serez d'accord, est le meilleur. Je veux les voir tous au même endroit, des experts, je peux donc choisir le meilleur des meilleurs. :-)


C'est là que je suis en désaccord. Le plus proche de votre code est l'approche basée sur la réflexion. Mais je choisirais un dictionnaire de délégués. Je pense que vous devez programmer à la langue plutôt que d'essayer de prendre une solution de langues à une langue où elle est mal adaptée. Personnellement, je n'aime pas l'approche de réflexion. J'éviterais la réflexion à moins qu'il n'y ait pas d'alternative propre. C'est le point de mon dernier paragraphe.


OK - Vous faites un excellent point: le plus proche de l'approche Delphi en C # ne sera pas le meilleur moyen de le faire en C #. Point pris. Voyons ce que le groupe vient d'autre avec ... Peut-être que vous obtiendrez le prix ... :-)


Un dictionnaire des délégués pourrait être le meilleur moyen ... un peu plus de travail mais propre et clair.


J'ai donné les points à Stig-Rune Skansgård, car il répondit directement à la question, mais j'ai fini par utiliser la solution de Martheen, ce qui est en effet un dictionnaire des délégués - beaucoup plus propre. Je suis d'accord, il est préférable de le faire la manière C # que d'imposer la voie Delphiti sur C #. Et je n'aime pas non plus la réflexion sauf quand elle est impérative. Si je trouve que je suis conduit à utiliser la réflexion, je commence à repenser mon approche de conception. Je suis un peu "puriste": affinez plutôt le design et le code que de s'appuyer sur "nouvelles notions invisibles" :-)



9
votes

Vous pouvez utiliser le type: xxx pré>

mais je pense que vous devez utiliser une méthode générique: p> xxx pré>

voici une variété pour paramétrée Construction: P>

public T Factory<T>(params object[] args): where T is MyBaseClass
{
    var argList = new List<object>(args);
    var type = typeof(T);
    var argtypes = argList.Select(o => o.GetType()).ToArray();
    var constructor = type.GetConstructor(argtypes);
    return constructor.Invoke(args) as T;
}


7 commentaires

Merci - va vérifier cela aussi. Une autre réponse utilise également Invoke () et j'ai vu du code sur le Web également l'utiliser dans des méthodes d'usine.


Notez que cela est un peu moins puissant que dans Delphi, comme vous ne pouvez pas appliquer / compter sur une sous-classe ayant un constructeur particulier. (Et il n'y a pas de contrainte générique pour les constructeurs à côté des paramètres sans paramètre en C #.)


@ O.R.Mapper: La contrainte de constructeur des génériques DELPHI est également pour les paramètres sans paramètre. Ce n'est que lorsque vous utilisez des classes méta que vous pouvez utiliser plus de constructeurs spécifiques tels que définis dans la hiérarchie de la classe à partir de TOBJECT à la classe que la classe META est définie sur.


@Marjanvenema: Exactement, je faisais référence à C # étant un peu inférieur aux métaclasses de Delphi.


@ Stig-rune skansgård - Je n'aurais pas non plus besoin du dictionnaire avec les touches basées surum à Delphi, mais le code est exécuté sur un serveur Web qui prend des demandes basées sur XML qui sont envoyées à l'usine, de sorte que les énumjets et un dictionnaire facilitent la tâche - peuvent facilement Représentant les énums en XML et envoyer le XML Enum directement à l'usine. Et bien sûr, parfois, j'utilise des constructeurs paramétrés.


@Mikey aha, alors je suppose que la première option est la voie à suivre, il suffit d'ajouter une construction paramétrée, etc. :)


@ Stig-rune Skansgård - Oui. Les deux options sont bonnes selon le contexte. Si je ne travaillais que dans un environnement pur Delphi ou C #, je ne passerais que la référence de type demandée à la méthode d'usine - aucun dictionnaire. J'avais négligé d'utiliser un constructeur paramétré dans mon exemple pour la simplicité, mais maintenant je l'ai ajouté.



4
votes
    class Potato
    {
    }

    class Potato1 : Potato
    {
        public Potato1(object[] param) { }
    }

    class Potato2 : Potato
    {
        public Potato2(object[] param);
    }

    enum MyEnum
    {
        E1, E2
    }

    Dictionary<MyEnum, Func<object[], Potato>> dict = new Dictionary<MyEnum, Func<object[], Potato>>(){
            {MyEnum.E1,(d)=>new Potato1(d)},
            {MyEnum.E2,(d)=>new Potato2(d)}
        };

    Potato Factory(MyEnum e, object[] param)
    {
        return dict[e](param);
    }

16 commentaires

Cela a l'air génial. Faudra vérifier. Mais est '=>' C # Syntaxe que je ne suis pas au courant ou avez-vous été mis à tort en c ++? Je pense que dans C #, vous devez envelopper le Constructor Func dans un type de délégué, etc.


@Mikey: C'est un Expression Lambda .


@O. R. MAPPER - OK merci. Je n'ai pas beaucoup utilisé .net beaucoup depuis 2.0, vs 2005. :-) Une des raisons de ma question est que je me demandais s'il y avait quelque chose de nouveau depuis lors pour aider à cela. Semble qu'il y a ...


N'est-ce pas dommage qu'il n'y ait pas de moneumum de ... dans C #


Est l'invoke nécessaire, ou pouvez-vous écrire dict [e] ()


"N'est-ce pas dommage qu'il n'y ait pas de moneumum de tableau". En effet. En dépit de toutes les choses cool il y a dans C #, c'est incroyable que certaines choses fondamentales que je prenne pour acquises dans l'objet Pascal ne sont tout simplement pas là en C #. C'est cet ADN C / C ++ ...


@DavidHeffernan Yea, il suffit de dicter [e] () est possible


Ces tableaux sont-ils myenum d'exister dans l'oxygène? Je suis curieux si ce n'est que la conception C # ou peut-être la limitation même .NET.


@Martheen qui existe dans l'oxygène. Meta Classes aussi je crois. Je ne pense pas que .Net impose de nombreuses limitations.


Doux. Peut-être une certaine extension à C # un jour pourrait ajouter cette fonctionnalité


@Martheen - Votre solution est assez élégante mais "Func" ne fonctionne que pour des méthodes sans paramétrage. J'ai donné un exemple simple dans ma question originale qui n'utilise pas de constructeur paramétré, mais j'ai généralement besoin de constructeurs paramétrés - j'ai édité la question maintenant.


@Mikey a édité ma réponse. objet [] pourrait être changé en exemple plus spécifique si vous en avez besoin?


@Martheen - OK- Je vais devoir vérifier cela aussi - semble très cool. Lorsque j'ai regardé le Func dans l'aide de MSDN, cela a déclaré que cela n'a fonctionné que pour des méthodes sans paramètres - mais je vois maintenant qu'il est surchargé et peut prendre des arguments supplémentaires ... beaucoup ont changé depuis .net 2.0 :)


@ Mikey Yea, la programmation fonctionnelle est essentiellement pourquoi je ne pourrai jamais retourner à Java (bien que cela puisse entrer Java cette année). Vous verrez que je ne répondez pas à votre question directement, je viens de tromper en incorporant une fonction dans un dictionnaire. La Lambda a contribué à rendre la solution soignée (elles sont réellement possibles dans .NET 2.0 sans Lambda, mais avec la syntaxe mal à niveau)


@Martheen: comprise, ce n'est pas une réponse directe. Mais avec Func et Lambda, il est élégant. Je pense que dans 2.0, vous avez déclaré un type de délégué, etc. Mais Delphi est toujours le mieux pour moi, maintenant qu'ils ont introduit des génériques et des méthodes anonymes. Pascal vous oblige virtuellement à écrire un code structuré et expressif et possède de superbes caractéristiques.non lambdas et sans linq, mais vous avez toujours la plus grande flexibilité - peut écrire un niveau très bas, ou très extrêmement extrêmement approprié pour la programmation fonctionnelle, le même modèle de OUM que C #. Le plus grand inconvénient est le manque de collecte automatisée des ordures, mais il existe des moyens de le faire aussi.


@Martheen: J'ai donné aux points Stig-Rune Skansgård, car il a répondu directement à la question, mais j'ai fini par utiliser votre solution, beaucoup plus propre. Comme David dit, mieux de le faire la manière C # que d'imposer la voie delphiti au C #. Et n'aime pas la réflexion sauf quand elle est impérative. Si je trouve que je suis conduit à utiliser la réflexion, je commence à repenser mon approche de conception. Delphi ne supporte pas la réflexion, mais quelque chose appelle RTTI, qui vous donne une "réflexion" limitée, évitez généralement d'utiliser cela aussi. Je suis un peu un «puriste», affinez plutôt la conception et le code que de dépendre des notions «nouvelles intimes». MDR