65 votes

Quelle est la différence entre new Object() et new Object{} dans les expressions en C# ?

J'ai l'extrait de code suivant :

Expression<Func<TSource, TDest>> expression = model => new TDest{};
// Result: {model => new TestModel(){}}

ReSharper refactorise ce snippet avec RedundantEmptyObjectOrCollectionInitializer réglage :

Expression<Func<TSource, TDest>> expression2 = model => new TDest();
// Result: {model => new TestModel()}

Après cela, mon code ne fonctionne pas. Quelle influence ont les accolades sur l'initialisation ?
J'ai trouvé Quelle est la différence entre new object() y new {} en C# ? sur Stack Overflow, mais les deux instances semblent égales.

expression.GetType().ToString() est égal à expression2.GetType().ToString()

Quelle est la différence entre ces initialisations dans les arbres d'expression ?

var a = model => new TDest{};
var b = model => new TDest();

2 votes

Que voulez-vous dire par "ne fonctionne pas" ? Pouvez-vous fournir un peu de code pour illustrer ce qui se passe pendant le remaniement ? Pensez à ajouter un exemple minimal reproductible .

0 votes

Linqpad génère exactement le même IL, et logiquement il n'y aura pas de différence puisqu'ils font la même chose (appeler un constructeur sans paramètres, puis définir 0 propriété). Vous avez peut-être mal diagnostiqué votre problème. Comme d'autres l'ont dit, veuillez fournir un MVCE, et une explication claire de votre erreur.

4 votes

@RB non, le PO est correct - voir ma réponse.

104voto

Marc Gravell Points 482669

En C# brut régulier, la réponse serait "rien". Cependant, lorsque l'on fait intervenir des arbres d'expression, il y a une différence ; comme on peut le constater aquí

using System;
using System.Linq.Expressions;
public class C<TSource, TDest> where TDest : new() {
    public Expression<Func<TSource, TDest>> Foo() => model => new TDest();
    public Expression<Func<TSource, TDest>> Bar() => model => new TDest {};
}

compile comme :

public Expression<Func<TSource, TDest>> Foo()
{
    ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "model");
    Expression arg_2E_0 = Expression.New(typeof(TDest));
    ParameterExpression[] expr_2A = new ParameterExpression[1];
    expr_2A[0] = parameterExpression;
    return Expression.Lambda<Func<TSource, TDest>>(arg_2E_0, expr_2A);
}

public Expression<Func<TSource, TDest>> Bar()
{
    ParameterExpression parameterExpression = Expression.Parameter(typeof(TSource), "model");
    Expression arg_38_0 = Expression.MemberInit(Expression.New(typeof(TDest)), Array.Empty<MemberBinding>());
    ParameterExpression[] expr_34 = new ParameterExpression[1];
    expr_34[0] = parameterExpression;
    return Expression.Lambda<Func<TSource, TDest>>(arg_38_0, expr_34);
}

Donc l'un d'entre eux implique un Expression.MemberInit (avec un ensemble vide de MemberBinding ) en plus des Expression.New . Cela peut perturber tout fournisseur LINQ (ou toute analyse similaire de l'arbre d'expression) qui ne s'y attend pas.

5voto

Alex.H Points 539

ReSharper vous donne une meilleure suggestion sur la manière d'instancier l'élément TDest classe.

En théorie, il n'y a pas de différence puisque les deux new TDest () y new TDest {} vous fournira une instance de TDest .

Cependant, lorsque vous utilisez l'expression d'initialisation, c'est parce que vous voulez définir les valeurs des propriétés ou des champs publics dans les fichiers TDest .

class TDest
{
    public string MyProperty { get; set; }
}

Vous pourriez donc initialiser le TDest qui fixe une valeur à MyProperty . Par exemple :

// Sample 1
new TDest { MyProperty = "This is the value of my property" };

// Sample 2
new TDest() { MyProperty = "This is the value of my property" };

Dans votre cas, votre classe a un constructeur sans paramètre, donc les deux, les ponctuateurs {, } ou des opérateurs () serait bien.

Pour les scénarios simples où vous disposez d'un constructeur sans paramètre, vous pouvez utiliser uniquement la fonction TDest() forme courte.

Mais si vous aviez par exemple la classe ci-dessous.

class TDest
{
    readonly ISomeInterface _someService;

    public string MyProperty { get; set; }

    public TDest(ISomeInterface someService)
    {
        _someService = someService;
    }
}

Et vous vouliez initialiser MyProperty avec quelque chose de différent de sa valeur d'initialisation par défaut (null, types de référence), vous pouvez utiliser l'initialisation complète de l'objet. Par exemple :

// Sample 3
new TDest(new MySomeServiceImplementation()) { MyProperty = "This is the value of my property" };

J'espère que cela vous aidera !

Pour vous faire une meilleure idée, allez jeter un coup d'œil à Initialiseurs d'objets C# .

0 votes

Cela explique l'utilisation de ces deux expressions dans des cas normaux, mais le PO demande une situation spécifique où elles sont utilisées. ne sont pas égal.

0 votes

@Pyritie, j'ai compris votre point de vue, ainsi que celui de l'OP, cependant si vous regardez de près la question est "Quelle est la différence entre ces initialisations : var a = new TDest{} ; var b = new TDest() ;" à laquelle j'ai répondu plus haut. Dans l'ensemble, en ajoutant les tresses d'expression au contexte, c'est comme Marc-Gravell l'a mentionné, le code compilé est différent sémantiquement.

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