68 votes

un constructeur en tant que délégué - est-ce possible en C #?

J'ai un cours comme ci-dessous:

 class Foo
{
  public Foo(int x) { ... }
}
 

et je dois passer à une certaine méthode un délégué comme celui-ci:

 delegate Foo FooGenerator(int x);
 

Est-il possible de passer directement le constructeur sous forme de valeur FooGenerator , sans avoir à taper:

 delegate(int x) { return new Foo(x); }
 

?

EDIT: Pour mon usage personnel, la question fait référence à .NET 2.0, mais les astuces / réponses pour la version 3.0+ sont également les bienvenues.

62voto

Marc Gravell Points 482669

Je suis en supposant que vous auriez normalement faire quelque chose comme ceci dans le cadre d'une usine de mise en œuvre, où les types réels ne sont pas connus au moment de la compilation...

Tout d'abord, notez qu'une approche plus facile peut-être un post-créer init étape, vous pouvez utiliser des génériques:

static T Create<T>({args}) where T : class, ISomeInitInterface, new() {
    T t = new T();
    t.Init(args);
    return t;
}

Vous pouvez ensuite utiliser MakeGenericMethod et/ou CreateDelegate.


Autrement, vous pouvez faire cela avec à la volée avec Expression (3.5) ou DynamicMethod (2.0); l' Expression approche est la plus simple (exemples sur le chemin...)

    var param = Expression.Parameter(typeof(int), "val");
    var ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    var lambda = Expression.Lambda<Func<int, Foo>>(
        Expression.New(ctor, param), param);
    var func = lambda.Compile();
    Foo foo = func(123);
    string s = foo.ToString(); // proof

et

    ConstructorInfo ctor = typeof(Foo).GetConstructor(new[] { typeof(int) });
    DynamicMethod dm = new DynamicMethod("Create", typeof(Foo),
            new Type[] { typeof(int) }, typeof(Foo), true);
    ILGenerator il = dm.GetILGenerator();
    il.Emit(OpCodes.Ldarg_0);
    il.Emit(OpCodes.Newobj, ctor);
    il.Emit(OpCodes.Ret);
    Converter<int, Foo> func = (Converter<int, Foo>)
        dm.CreateDelegate(typeof(Converter<int, Foo>));        
    Foo foo = func(123);
    string s = foo.ToString(); // proof

37voto

leppie Points 67289

Non, le CLR ne permet pas de lier les délégués à ConstructorInfo .

Vous pouvez cependant simplement créer votre propre:

 static T Make<T>(Action<T> init) where T : new()
{
  var t = new T();
  init(t);
  return t;
}
 

Usage

 var t = Make<Foo>( x => { x.Bar = "bar"; x.Baz = 1; });
 

10voto

Adam Robinson Points 88472

Je pense aussi concis que vous allez obtenir (sans passer à un modèle d'usine) serait quelque chose avec des méthodes anonymes, comme ceci:

 delegate Foo FooGenerator(int x);

...    

void DoStuff()
{
    YourDelegateConsumer(x => new Foo(x));
}
 

Cela ne fait pas strictement ce que vous avez demandé (puisque vous passez un délégué à une méthode anonyme qui retourne une nouvelle instance, plutôt qu'un délégué direct au constructeur), mais je ne pense pas que vous demandiez est strictement possible.

Ceci, bien sûr, en supposant que vous utilisez 3.5+

6voto

Mongus Pong Points 6902

Il semble que vous souhaitiez probablement utiliser le modèle de fabrique de classe.

Modèle de méthode d'usine

2voto

Andrew Hare Points 159332

Malheureusement non, les constructeurs ne sont pas tout à fait les mêmes que les méthodes et vous ne pouvez donc pas créer de délégué qui les pointe. C’est une idée intéressante, mais avec plus d’informations, nous pourrions concevoir une solution de contournement qui serait similaire sur le plan syntaxique.

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