Обходное решение из-за отсутствия 'nameof' оператора в C# для безопасной с точки зрения типов привязки данных?

44
задан DavidRR 8 September 2016 в 18:28
поделиться

4 ответа

Этот код в основном делает это:

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;
    }
}

(Конечно, это - 3,5 кода...)

77
ответ дан reshefm 26 November 2019 в 21:56
поделиться

В то время как reshefm и Jon Skeet показывают надлежащий способ сделать это использование выражения, должно стоить отметить, что существует более дешевый способ сделать это для имен методов:

Обертка делегат вокруг Вашего метода, получите MethodInfo, и Вы хороши для движения. Вот пример:

private void FuncPoo()
{
}

...

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

, К сожалению, это работает только на методы; это не работает на свойства, поскольку у Вас не может быть делегатов в методах получателя свойства или методах установщика. (Походит на глупое ограничение, IMO.)

6
ответ дан Judah Gabriel Himango 26 November 2019 в 21:56
поделиться

Обходное решение должно использовать дерево выражений, и демонтировать то дерево выражений для нахождения соответствующего MemberInfo. Существует немного больше детали и комментария в это примечание (хотя не код для выведения участника - это находится в другом ТАК вопрос где-нибудь, я верю).

, К сожалению, поскольку деревья выражений не существуют в.NET 2.0, нет действительно никакого эквивалента.

Одно решение избежать опечаток состоит в том, чтобы иметь ряд средств доступа, которые выбирают соответствующее PropertyInfo для особого свойства и модульного теста их. Это было бы единственным местом, которое имело строку в нем. Это избежало бы дублирования и сделало бы рефакторинг легче, но это является немного драконовским.

4
ответ дан Jon Skeet 26 November 2019 в 21:56
поделиться

Расширение к тому, что сделал reshefm, упростило использование оператора nameof(), а также дало имена методов, членов и методов класса:

/// <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");
    }
}

Использовать его:

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.
    }
}
4
ответ дан 26 November 2019 в 21:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: