[C#] Ruft den Namen der Eigenschaft als Zeichenfolge ab



Answers

Mit C # 6.0 ist dies jetzt kein Problem mehr, da Sie Folgendes tun können:

nameof(SomeProperty)

Dieser Ausdruck wird zur Kompilierzeit in "SomeProperty" .

MSDN-Dokumentation von nameof .

Question

(Siehe Lösung, die ich mit der Antwort erstellt habe, die ich akzeptiert habe)

Ich versuche, die Wartbarkeit von Code mit Reflektion zu verbessern. Die App verfügt über eine .NET Remoting-Schnittstelle, die (unter anderem) eine Methode namens "Execute" für den Zugriff auf Teile der App bereitstellt, die nicht in der veröffentlichten Remote-Schnittstelle enthalten sind.

So bezeichnet die App Eigenschaften (in diesem Beispiel eine statische), die über Execute erreichbar sein sollen:

RemoteMgr.ExposeProperty("SomeSecret", typeof(SomeClass), "SomeProperty");

So könnte ein entfernter Benutzer anrufen:

string response = remoteObject.Execute("SomeSecret");

und die App würde Reflection verwenden, um SomeClass.SomeProperty zu finden und ihren Wert als String zurückzugeben.

Wenn jemand SomeProperty umbenennt und vergisst, den dritten Parameter von ExposeProperty () zu ändern, wird dieser Mechanismus leider aufgehoben.

Ich muss das Äquivalent von:

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()

Um in ExposeProperty als 3. Parm zu verwenden, würden Refactoring-Tools für Umbenennungen sorgen.

Gibt es eine Möglichkeit, dies zu tun? Danke im Voraus.

Okay, hier ist, was ich am Ende erstellt habe (basierend auf der Antwort, die ich ausgewählt habe und der Frage, auf die er verwiesen hat):

// <summary>
// Get the name of a static or instance property from a property access lambda.
// </summary>
// <typeparam name="T">Type of the property</typeparam>
// <param name="propertyLambda">lambda expression of the form: '() => Class.Property' or '() => object.Property'</param>
// <returns>The name of the property</returns>
public string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    var me = propertyLambda.Body as MemberExpression;

    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    return me.Member.Name;
 }

Verwendung:

// Static Property
string name = GetPropertyName(() => SomeClass.SomeProperty);

// Instance Property
string name = GetPropertyName(() => someObject.SomeProperty);

Mit dieser coolen Funktion ist es nun an der Zeit, die ExposeProperty-Methode zu vereinfachen. Polieren von Türklinken ist eine gefährliche Arbeit ...

Danke an alle.







Basierend auf der Antwort, die bereits in der Frage und auf diesem Artikel ist: https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/ I präsentiere meine Lösung für dieses Problem:

public static class PropertyNameHelper
{
    /// <summary>
    /// A static method to get the Propertyname String of a Property
    /// It eliminates the need for "Magic Strings" and assures type safety when renaming properties.
    /// See: http://.com/questions/2820660/get-name-of-property-as-a-string
    /// </summary>
    /// <example>
    /// // Static Property
    /// string name = PropertyNameHelper.GetPropertyName(() => SomeClass.SomeProperty);
    /// // Instance Property
    /// string name = PropertyNameHelper.GetPropertyName(() => someObject.SomeProperty);
    /// </example>
    /// <typeparam name="T"></typeparam>
    /// <param name="propertyLambda"></param>
    /// <returns></returns>
    public static string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
    {
        var me = propertyLambda.Body as MemberExpression;

        if (me == null)
        {
            throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
        }

        return me.Member.Name;
    }
    /// <summary>
    /// Another way to get Instance Property names as strings.
    /// With this method you don't need to create a instance first.
    /// See the example.
    /// See: https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/
    /// </summary>
    /// <example>
    /// string name = PropertyNameHelper((Firma f) => f.Firmenumsatz_Waehrung);
    /// </example>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TReturn"></typeparam>
    /// <param name="expression"></param>
    /// <returns></returns>
    public static string GetPropertyName<T, TReturn>(Expression<Func<T, TReturn>> expression)
    {
        MemberExpression body = (MemberExpression)expression.Body;
        return body.Member.Name;
    }
}

Und ein Test, der auch die Verwendung für Beispiel und statische Eigenschaften zeigt:

[TestClass]
public class PropertyNameHelperTest
{
    private class TestClass
    {
        public static string StaticString { get; set; }
        public string InstanceString { get; set; }
    }

    [TestMethod]
    public void TestGetPropertyName()
    {
        Assert.AreEqual("StaticString", PropertyNameHelper.GetPropertyName(() => TestClass.StaticString));

        Assert.AreEqual("InstanceString", PropertyNameHelper.GetPropertyName((TestClass t) => t.InstanceString));
    }
}



Okay, hier ist, was ich am Ende erstellt habe (basierend auf der Antwort, die ich ausgewählt habe und der Frage, auf die er verwiesen hat):

// <summary>
// Get the name of a static or instance property from a property access lambda.
// </summary>
// <typeparam name="T">Type of the property</typeparam>
// <param name="propertyLambda">lambda expression of the form: '() => Class.Property' or '() => object.Property'</param>
// <returns>The name of the property</returns>

public string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    var me = propertyLambda.Body as MemberExpression;

    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    return me.Member.Name;
 }

Verwendung:

// Static Property
string name = GetPropertyName(() => SomeClass.SomeProperty);

// Instance Property
string name = GetPropertyName(() => someObject.SomeProperty);



Sie können Reflection verwenden, um die tatsächlichen Namen der Eigenschaften abzurufen.

http://www.csharp-examples.net/reflection-property-names/

Wenn Sie eine Eigenschaft verwenden müssen, um einer Eigenschaft einen "String-Namen" zuzuweisen, warum schreiben Sie dann kein Attribut, über das Sie nachdenken können, um den String-Namen zu erhalten?

[StringName("MyStringName")]
private string MyProperty
{
    get { ... }
}



Ich hatte einige Schwierigkeiten mit den Lösungen, die für meinen speziellen Anwendungsfall bereits vorgeschlagen wurden, aber ich habe es irgendwann herausgefunden. Ich glaube nicht, dass mein spezifischer Fall einer neuen Frage würdig ist, deshalb poste ich meine Lösung hier als Referenz. (Dies ist sehr eng mit der Frage verwandt und bietet eine Lösung für jeden anderen mit einem ähnlichen Fall zu meinem).

Der Code, mit dem ich endete, sieht so aus:

public class HideableControl<T>: Control where T: class
{
    private string _propertyName;
    private PropertyInfo _propertyInfo;

    public string PropertyName
    {
        get { return _propertyName; }
        set
        {
            _propertyName = value;
            _propertyInfo = typeof(T).GetProperty(value);
        }
    }

    protected override bool GetIsVisible(IRenderContext context)
    {
        if (_propertyInfo == null)
            return false;

        var model = context.Get<T>();

        if (model == null)
            return false;

        return (bool)_propertyInfo.GetValue(model, null);
    }

    protected void SetIsVisibleProperty(Expression<Func<T, bool>> propertyLambda)
    {
        var expression = propertyLambda.Body as MemberExpression;
        if (expression == null)
            throw new ArgumentException("You must pass a lambda of the form: 'vm => vm.Property'");

        PropertyName = expression.Member.Name;
    }
}

public interface ICompanyViewModel
{
    string CompanyName { get; }
    bool IsVisible { get; }
}

public class CompanyControl: HideableControl<ICompanyViewModel>
{
    public CompanyControl()
    {
        SetIsVisibleProperty(vm => vm.IsVisible);
    }
}

Der wichtige Teil für mich ist, dass der Compiler in der CompanyControl Klasse nur eine boolesche Eigenschaft von ICompanyViewModel , die es anderen Entwicklern leichter macht, sie richtig zu machen.

Der Hauptunterschied zwischen meiner Lösung und der akzeptierten Antwort besteht darin, dass meine Klasse generisch ist und ich nur Eigenschaften des generischen Typs, die boolesch sind, abgleichen möchte.




Links