it-swarm.com.de

Liefert den Namen der Eigenschaft als String

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

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

So bestimmt die App Eigenschaften (in diesem Beispiel eine statische), auf die über Ausführen zugegriffen werden soll:

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 3. Parm von ExposeProperty () zu ändern, unterbricht dies diesen Mechanismus.

Ich muss das Äquivalent von: 

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()

als 3. Parameter in ExposeProperty verwenden, so dass die Umgestaltungstools die Umbenennung übernehmen.

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

Okay, hier ist das, was ich am Ende erstellt habe (basierend auf meiner Antwort und der Frage, auf die er sich bezieht):

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

Verwendungszweck:

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

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

Mit dieser coolen Funktion wird es nun Zeit, die ExposeProperty-Methode zu vereinfachen. Das Polieren von Türknöpfen ist eine gefährliche Arbeit ...

Vielen Dank an alle.

169
Jim C

Verwenden Sie GetMemberInfo von hier: Abrufen des Eigenschaftsnamens aus dem Lambda-Ausdruck Sie können Folgendes tun:

RemoteMgr.ExposeProperty(() => SomeClass.SomeProperty)

public class SomeClass
{
    public static string SomeProperty
    {
        get { return "Foo"; }
    }
}

public class RemoteMgr
{
    public static void ExposeProperty<T>(Expression<Func<T>> property)
    {
        var expression = GetMemberInfo(property);
        string path = string.Concat(expression.Member.DeclaringType.FullName,
            ".", expression.Member.Name);
        // Do ExposeProperty work here...
    }
}

public class Program
{
    public static void Main()
    {
        RemoteMgr.ExposeProperty("SomeSecret", () => SomeClass.SomeProperty);
    }
}
59
Daniel Renshaw

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

nameof(SomeProperty)

Dieser Ausdruck wird zur Kompilierzeit in "SomeProperty" aufgelöst.

MSDN-Dokumentation des Namens von .

346
James Ko

Es gibt einen bekannten Hack, um ihn aus dem Lambda-Ausdruck zu extrahieren (dies ist aus der PropertyObserver-Klasse von Josh Smith in seiner MVVM-Stiftung):

    private static string GetPropertyName<TPropertySource>
        (Expression<Func<TPropertySource, object>> expression)
    {
        var lambda = expression as LambdaExpression;
        MemberExpression memberExpression;
        if (lambda.Body is UnaryExpression)
        {
            var unaryExpression = lambda.Body as UnaryExpression;
            memberExpression = unaryExpression.Operand as MemberExpression;
        }
        else
        {
            memberExpression = lambda.Body as MemberExpression;
        }

        Debug.Assert(memberExpression != null, 
           "Please provide a lambda expression like 'n => n.PropertyName'");

        if (memberExpression != null)
        {
            var propertyInfo = memberExpression.Member as PropertyInfo;

            return propertyInfo.Name;
        }

        return null;
    }

Entschuldigung, es fehlte etwas Kontext. Dies war Teil einer größeren Klasse, wobei TPropertySource die Klasse ist, die die Eigenschaft enthält. Sie können die Funktion in TPropertySource als generisch definieren, um sie aus der Klasse zu extrahieren. Ich empfehle einen Blick auf den vollständigen Code der MVVM Foundation .

17
Dan Bryant

Okay, hier ist das, was ich am Ende erstellt habe (basierend auf meiner Antwort und der Frage, auf die er sich bezieht):

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

Verwendungszweck:

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

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

Die PropertyInfo -Klasse sollte Ihnen helfen, wenn Sie dies richtig verstehen.

  1. Type.GetProperties () - Methode

    PropertyInfo[] propInfos = typeof(ReflectedType).GetProperties();
    propInfos.ToList().ForEach(p => 
        Console.WriteLine(string.Format("Property name: {0}", p.Name));
    

Ist das was du brauchst?

7

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

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

Wenn Sie einen Weg benötigen, um einer Eigenschaft einen "String-Namen" zuzuweisen, schreiben Sie ein Attribut, das Sie überdenken können, um den String-Namen zu erhalten.

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

Ich habe Ihre Lösung so geändert, dass sie über mehrere Eigenschaften verkettet werden kann:

public static string GetPropertyName<T>(Expression<Func<T>> propertyLambda)
{
    MemberExpression me = propertyLambda.Body as MemberExpression;
    if (me == null)
    {
        throw new ArgumentException("You must pass a lambda of the form: '() => Class.Property' or '() => object.Property'");
    }

    string result = string.Empty;
    do
    {
        result = me.Member.Name + "." + result;
        me = me.Expression as MemberExpression;
    } while (me != null);

    result = result.Remove(result.Length - 1); // remove the trailing "."
    return result;
}

Verwendungszweck:

string name = GetPropertyName(() => someObject.SomeProperty.SomeOtherProperty);
// returns "SomeProperty.SomeOtherProperty"
5
hypehuman

Basierend auf der Antwort, die bereits in der Frage enthalten ist, und auf diesen Artikel: https://handcraftsman.wordpress.com/2008/11/11/wie -/Ich 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://stackoverflow.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 zum 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));
    }
}
4
Thomas

Alte Frage, aber eine andere Antwort auf diese Frage ist das Erstellen einer statischen Funktion in einer Hilfsklasse, die das CallerMemberNameAttribute verwendet.

public static string GetPropertyName([CallerMemberName] String propertyName = null) {
  return propertyName;
}

Und dann verwenden Sie es wie:

public string MyProperty {
  get { Console.WriteLine("{0} was called", GetPropertyName()); return _myProperty; }
}
3
Jim Pedid

so habe ich es implementiert. Der Grund dafür ist, wenn die Klasse, deren Namen Sie von ihrem Member erhalten möchten, nicht statisch ist, müssen Sie eine Instanz davon erstellen und dann den Namen des Members erhalten. so generisch kommt hier zu helfen

public static string GetName<TClass>(Expression<Func<TClass, object>> exp)
{
    MemberExpression body = exp.Body as MemberExpression;

    if (body == null)
    {
         UnaryExpression ubody = (UnaryExpression)exp.Body;
         body = ubody.Operand as MemberExpression;
    }

     return body.Member.Name;
}

die Verwendung ist so 

var label = ClassExtension.GetName<SomeClass>(x => x.Label); //x is refering to 'SomeClass'
0
Mo Hrad A

Sie können die StackTrace-Klasse verwenden, um den Namen der aktuellen Funktion abzurufen (oder, wenn Sie den Code in eine Funktion einfügen, dann eine Stufe herunterfahren und die aufrufende Funktion aufrufen).

Siehe http://msdn.Microsoft.com/de-de/library/system.diagnostics.stacktrace(VS.71).aspx

0
Sprotty

Ich habe diese Antwort mit großer Wirkung verwendet: Holen Sie die Eigenschaft als Zeichenfolge aus einem Ausdruck <Func <TModel, TProperty >>

Ich weiß, dass ich diese Frage schon vor einiger Zeit beantwortet habe. Der einzige Vorteil, den meine andere Antwort hat, ist, dass sie für statische Eigenschaften funktioniert. Ich finde die Syntax in dieser Antwort viel nützlicher, da Sie keine Variable des Typs erstellen müssen, den Sie widerspiegeln möchten.

0
hypehuman

Ich hatte einige Schwierigkeiten bei der Verwendung der Lösungen, die bereits für meinen speziellen Anwendungsfall vorgeschlagen wurden, habe es aber letztendlich herausgefunden. Ich glaube nicht, dass mein konkreter Fall eine neue Frage verdient, deshalb stelle ich meine Lösung hier als Referenz vor. (Dies ist sehr eng mit der Frage verbunden und bietet eine Lösung für alle anderen Personen, die einen ähnlichen Fall haben wie ich).

Der Code, den ich am Ende erhalten habe, 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);
    }
}

Für mich ist es wichtig, dass der Compiler in der CompanyControl-Klasse mir nur die Möglichkeit gibt, eine boolesche Eigenschaft von ICompanyViewModel auszuwählen, die es anderen Entwicklern erleichtert, sie richtig zu machen.

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

0
bikeman868