44 votes

solutions de contournement de l'opérateur nameof() en C# : liaison de données sécurisée par type de données

De nombreux souhaits ont été exprimés pour inclure l'opérateur nameof () dans C#, afin que vous puissiez faire, par exemple, nameof (Customer.Name), qui vous renverra "Name".

J'ai un objet de domaine. Et je dois le lier. Et j'ai besoin des noms des propriétés en tant que chaînes de caractères. Et je veux qu'ils soient sécurisés.

Je me souviens qu'il y avait une solution de contournement pour .NET 3.5 qui impliquait des expressions lambda, de sorte que vous pouviez obtenir l'effet de l'opérateur "nameof" manquant, mais je n'ai pas pu le trouver maintenant. Quelqu'un peut me le rappeler ? Et... pour .NET 2.0... y a-t-il un moyen de le faire ? Merci !

77voto

reshefm Points 1719

Ce code fait essentiellement cela :

class Program
{
    static void Main()
    {
        var propName = Nameof<SampleClass>.Property(e => e.Name);

        Console.WriteLine(propName);
    }
}

public class Nameof<T>
{
    public static string Property<TProp>(Expression<Func<T, TProp>> expression)
    {
        var body = expression.Body as MemberExpression;
        if(body == null)
            throw new ArgumentException("'expression' should be a member expression");
        return body.Member.Name;
    }
}

(Bien sûr, c'est un code 3,5...)

6voto

Judah Himango Points 27365

Bien que reshefm et Jon Skeet montrent la bonne façon de procéder en utilisant des expressions, il convient de noter qu'il existe une façon moins coûteuse de procéder pour les noms de méthodes :

Enveloppez un délégué autour de votre méthode, obtenez le MethodInfo, et vous êtes prêt à partir. Voici un exemple :

private void FuncPoo()
{
}

...

// Get the name of the function
string funcName = new Action(FuncPoo).Method.Name;

Malheureusement, cela ne fonctionne que pour les méthodes ; cela ne fonctionne pas pour les propriétés, car vous ne pouvez pas avoir de délégués aux méthodes getter ou setter des propriétés. (Cela semble être une limitation stupide, IMO).

4voto

Ad P. Points 21

Une extension de ce que reshefm a fait, qui simplifie l'utilisation de l'opérateur nameof(), et donne les noms des méthodes et des membres de la classe ainsi que les méthodes :

/// <summary>
/// Provides the <see cref="nameof"/> extension method that works as a workarounds for a nameof() operator, 
/// which should be added to C# sometime in the future.
/// </summary>
public static class NameOfHelper
{
    /// <summary>
    /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression.
    /// </summary>
    /// <typeparam name="T">The type of the <paramref name="obj"/> parameter.</typeparam>
    /// <typeparam name="TProp">The type of the property (or the method's return type), which is used in the <paramref name="expression"/> parameter.</typeparam>
    /// <param name="obj">An object, that has the property (or method), which its name is returned.</param>
    /// <param name="expression">A Lambda expression of this pattern: x => x.Property <BR/>
    /// Where the x is the <paramref name="obj"/> and the Property is the property symbol of x.<BR/>
    /// (For a method, use: x => x.Method()</param>
    /// <returns>A string that has the name of the given property (or method).</returns>
    public static string nameof<T, TProp>(this T obj, Expression<Func<T, TProp>> expression)
    {
        MemberExpression memberExp = expression.Body as MemberExpression;
        if (memberExp != null)
            return memberExp.Member.Name;

        MethodCallExpression methodExp = expression.Body as MethodCallExpression;
        if (methodExp != null)
            return methodExp.Method.Name;

        throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression");
    }

    /// <summary>
    /// Returns a string represantaion of a property name (or a method name), which is given using a lambda expression.
    /// </summary>
    /// <typeparam name="TProp">The type of the property (or the method's return type), which is used in the <paramref name="expression"/> parameter.</typeparam>
    /// <param name="expression">A Lambda expression of this pattern: () => x.Property <BR/>
    /// Where Property is the property symbol of x.<BR/>
    /// (For a method, use: () => x.Method()</param>
    /// <returns>A string that has the name of the given property (or method).</returns>
    public static string nameof<TProp>(Expression<Func<TProp>> expression)
    {
        MemberExpression memberExp = expression.Body as MemberExpression;
        if (memberExp != null)
            return memberExp.Member.Name;

        MethodCallExpression methodExp = expression.Body as MethodCallExpression;
        if (methodExp != null)
            return methodExp.Method.Name;

        throw new ArgumentException("'expression' should be a member expression or a method call expression.", "expression");
    }
}

Pour l'utiliser :

static class Program
{
    static void Main()
    {
        string strObj = null;
        Console.WriteLine(strObj.nameof(x => x.Length)); //gets the name of an object's property.
        Console.WriteLine(strObj.nameof(x => x.GetType())); //gets the name of an object's method.
        Console.WriteLine(NameOfHelper.nameof(() => string.Empty)); //gets the name of a class' property.
        Console.WriteLine(NameOfHelper.nameof(() => string.Copy(""))); //gets the name of a class' method.
    }
}

4voto

Jon Skeet Points 692016

La solution de contournement consiste à utiliser un arbre d'expression, et à décomposer cet arbre d'expression pour trouver les éléments pertinents. MemberInfo . Il y a un peu plus de détails et de commentaires dans cette note (mais pas le code pour sortir le membre - c'est dans une autre question SO quelque part, je crois).

Malheureusement, comme les arbres d'expression n'existent pas dans .NET 2.0, il n'y a pas vraiment d'équivalent.

Une solution pour éviter les fautes de frappe consiste à disposer d'un ensemble d'accesseurs qui récupèrent les données pertinentes. PropertyInfo pour une propriété particulière, et les tester en unité. Ce serait le seul endroit qui contiendrait la chaîne de caractères. Cela éviterait la duplication et faciliterait la refactorisation, mais c'est un peu draconien.

1voto

Ian Ringrose Points 19115

Si vous faites de la liaison de données, jetez un coup d'oeil à "Comment rendre le Databinding sûr et supporter le refactoring"

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