3 votes

Comment initier une classe sans utiliser le mot-clé "new" ?

Cela pourrait être une question stupide, mais je suis en train de développer un composant et j'ai une classe avec une propriété comme suit

public class Grid()
{
 ..
 public IDecorator Decorator { get; set;}

}

Ce que je veux, c'est que l'utilisateur spécifie sa propre classe personnalisée qui implémente IDecorator de la manière suivante

...BuildGrid(
grid=>{
..
grid.Decorator =  [CustomNameSpace].[DecoratorClass] 
//comme
grid.Decorator =  Com.MyCompany.DivDecorator
..
});

Com.MyCompany.DivDecorator implémente l'interface IDecorator. Donc comment devrais-je faire pour que l'utilisateur final ne spécifie pas le mot-clé "new" comme dans

grid.Decorator = new Com.MyCompany.DivDecorator();

Je sais que je passe à côté d'un concept clé en C# ici.

Merci

[Éditer]

J'essayais de faire quelque chose comme la bibliothèque Java DisplayTag située ici

http://www.displaytag.org/1.2/tut_decorators.html

La façon dont ils le font est par

... decorator="org.displaytag.sample.Wrapper"

Alors je suppose qu'au lieu de

public IDecorator Decorator { get; set;}

Je devrais faire

public String Decorator { get; set;}

et ensuite utiliser TypeOf() en interne pour le résoudre.... Je me demande juste s'il y a une autre façon élégante de le faire en C#.

Merci

8voto

p.s.w.g Points 81433

Vous pouvez utiliser une méthode de fabrique :

public class DivDecorator
{
    public static IDecorator Create()
    {
        return new Com.MyCompany.DivDecorator()
    }
}

...

grid.Decorator = Com.MyCompany.DivDecorator.Create();

Ou un singleton :

public class DivDecorator
{
    public static readonly IDecorator Instance = new DivDecorator();
}

...

grid.Decorator = Com.MyCompany.DivDecorator.Instance;

Dans les deux cas, vous déplacez simplement l'opérateur new vers un endroit différent.

Alternativement, vous pourriez demander à l'utilisateur de spécifier le type, puis vous devrez vous soucier de l'instancier quand vous en avez besoin :

public class Grid
{
    public Type DecoratorType { get; set; }

    private IDecorator CreateDecorator()
    {
        return (IDecorator)Activator.CreateInstance(this.DecoratorType);
    }
}

...

grid.Decorator = typeof(Com.MyCompany.DivDecorator);

Ou encore mieux, utilisez les génériques :

public class Grid where T : IDecorator, new
{
    private T CreateDecorator()
    {
        return new T();
    }
}

BuildGrid(grid => ... );

5voto

Joe Enos Points 17442

Si je comprends ce que vous recherchez, vous pouvez utiliser un générique :

public class Grid where TDecorator : IDecorator, new() {

    private readonly TDecorator _decorator;

    public Grid() {
        _decorator = new TDecorator();
    }

    public TDecorator Decorator { get { return _decorator; } }
}

Ils obtiendraient une grille en appelant :

var myGrid = new Grid();

3voto

Mark Sowul Points 4249

Vous pourriez rendre BuildGrid générique et spécifier une contrainte new().

par exemple BuildGrid() where T : IDecorator, new()

Je ne suis cependant pas sûr à 100% de ce que vous essayez d'obtenir.

1voto

phil soady Points 4463

Étant donné que vous avez une interface, vous créerez une instance quelque part. Vous pouvez l'injecter (voir les schémas IOC, ou un schéma de fabrique d'instances)

Il existe divers scénarios. mais comprendre les schémas de fabrique vous aidera

1) La classe se trouve à l'intérieur de l'assembly. découvrez le/les type(s) Obtenir tous les types qui implémentent une interface et créez une instance http://msdn.microsoft.com/en-us/library/wccyzw83.aspx

2) Le code est externe, http://msdn.microsoft.com/en-us/library/dd460648.aspx

3) Ou un fichier http://msdn.microsoft.com/en-us/library/system.reflection.assembly.load%28v=vs.110%29.aspx

0voto

Merci à tous ceux qui m'ont aidé ! J'ai décidé d'opter pour la méthode Activator.CreateInstance de p.s.w.g. La raison en est que, pour le Composant Grid, j'ai un décorateur au niveau de la table et ensuite chaque colonne du tableau peut également avoir son propre décorateur. Comme dans

@Model.[MyIEnumberable].BuildGrid(grid=>{
grid.ShowHeader = false;
grid.CellSpacing = 0;
grid.CellPadding = 0;
grid.Decorator = "Com.MyCompany.DivDecorator";
grid.columns(
        grid.column(HeaderText: "First Column", Decorator:"Com.MyCompany.FirstColumnDecorator"...),
        grid.column(HeaderText: "Second Column", Decorator:"Com.MyCompany.SecondColumnDecorator"..),
        grid.column(HeaderText: "ThirdColumn", Text:@item.ProductID),
        grid.column(HeaderText: "ThirdColumn", Text:@item.[A Property only exist in grid.Decorator, achieved using dynamic/DynamicObject])
)
})

Donc, vu ma situation et étant donné que chaque colonne peut éventuellement avoir sa propre classe décoratrice. Je devrai donc utiliser Activator.CreateInstance pour elles.

Merci à tous une fois de plus pour votre aide !! J'apprécie grandement votre temps une fois de plus!!

[Edit]. Après avoir lu les deux derniers commentaires de p.s.w.g, la méthode générique est la solution à adopter !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X