एक स्ट्रिंग के रूप में संपत्ति का नाम प्राप्त करें


203

(मेरे द्वारा स्वीकृत उत्तर का उपयोग करके नीचे दिए गए समाधान देखें)

मैं प्रतिबिंब को शामिल करने वाले कुछ कोड की स्थिरता को बेहतर बनाने की कोशिश कर रहा हूं। ऐप में .NET रीमोटिंग इंटरफ़ेस एक्सपोज़िंग (अन्य बातों के अलावा) है जो ऐप के भागों को एक्सेस करने के लिए एक्सक्यूट नामक एक विधि है जो इसके प्रकाशित रिमोट इंटरफ़ेस में शामिल नहीं है।

यहां बताया गया है कि ऐप किस प्रकार संपत्तियों को नामित करता है (इस उदाहरण में एक स्थिर) जो कि एक्सेक्यूट के माध्यम से सुलभ होना है:

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

इसलिए एक दूरस्थ उपयोगकर्ता कॉल कर सकता है:

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

और ऐप SomeClass.SomeProperty को खोजने के लिए प्रतिबिंब का उपयोग करेगा और एक स्ट्रिंग के रूप में इसके मूल्य को वापस करेगा।

दुर्भाग्यवश, यदि कोई व्यक्ति कुछProProperty का नाम बदल देता है और ExposeProperty () के 3 parm को बदलना भूल जाता है, तो यह इस तंत्र को तोड़ देता है।

मुझे इसके बराबर की आवश्यकता है:

SomeClass.SomeProperty.GetTheNameOfThisPropertyAsAString()

ExposeProperty में 3rd parm के रूप में उपयोग करने के लिए इसलिए रीफैक्टरिंग उपकरण नाम बदलने का ध्यान रखेंगे।

क्या इसे करने का कोई तरीका है? अग्रिम में धन्यवाद।

ठीक है, यहाँ मैंने क्या बनाया है (मेरे द्वारा चुने गए उत्तर और उसके द्वारा संदर्भित प्रश्न के आधार पर):

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

उपयोग:

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

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

अब इस शांत क्षमता के साथ, एक्सपोज़प्रोपर्टी विधि को सरल बनाने का समय है। खतरनाक कामों को चमकाने का काम ...

सबको धन्यवाद।


9
इसका सच में आभास है कि आपने अपना समाधान जोड़ा है और चीजों को बांधा है।
बस जी।


आपको अपने समाधान को उत्तर के रूप में जोड़ना चाहिए - यह आपके स्वीकृत उत्तर की तुलना में बहुत अधिक संक्षिप्त है।
केनी एविट

1
@ केनी एविट: डन:)
जिम सी

@ JimC अपग्रेड किया गया! और वर्तमान में स्वीकृत जवाब पर एक टिप्पणी में जुड़ा हुआ है । धन्यवाद!
केनी एविट

जवाबों:


61

यहाँ से GetMemberInfo का उपयोग करना: लंबोदर एक्सप्रेशन से प्रॉपर्टी का नाम आप इस तरह से कर सकते हैं:

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

वह पूरी तरह से शांत है। ऐसा लगता है कि यह किसी भी संपत्ति के प्रकार पर भी काम करेगा।
जिम सी

मैंने इसे केवल उदाहरण और स्थिर गुणों के साथ आज़माया। अब तक सब ठीक है।
जिम सी

कोई भी विचार जहां मुझे विधानसभा या NuGet पैकेज मिल सकता है जिसमें शामिल है GetMemberInfo? मुझे Microsoft एंटरप्राइज़ लाइब्रेरी के लिए 'सामान्य उपयोगिताओं' पैकेज के साथ कुछ भी नहीं मिल रहा है, जो एमएसडीएन को लगता है कि उस पद्धति में है। वहाँ एक "अनौपचारिक" पैकेज है लेकिन अनौपचारिक होने के नाते यह स्पष्ट नहीं है। जीएमसी का उत्तर , जो इस पर आधारित है, बहुत अधिक संक्षिप्त है और एक अनुपलब्ध पुस्तकालय पर भरोसा नहीं करता है।
केनी एविट

1
@KennyEvitt, जिस विधि को वह संदर्भित कर रहा है वह उस प्रश्न के लेखक द्वारा लिखी गई है जिसे उसने जोड़ा है। उस मेथोडीओ के लिए इस प्रकार का उपयोग कर सकते हैं। GetMembers msdn.microsoft.com/en-us/library/…
Bon

464

C # 6.0 के साथ, यह अब एक गैर-मुद्दा है जैसा कि आप कर सकते हैं:

nameof(SomeProperty)

यह अभिव्यक्ति संकलन-समय पर हल हो गई है "SomeProperty"

नाम का MSDN प्रलेखन


18
यह ModelState.AddModelError कॉल के लिए बदमाश और बहुत उपयोगी है।
माइकल सिल्वर

9
और यह एक है const string! कमाल
जैक

4
@RaidenCore यकीन है, यदि आप एक माइक्रोकंट्रोलर के लिए लिख रहे हैं, तो आपको सी जैसी निम्न-स्तरीय भाषा का उपयोग करना चाहिए, और यदि आपको छवि और वीडियो प्रसंस्करण जैसे प्रदर्शन के हर बिट को निचोड़ने की आवश्यकता है, तो आपको C या C ++ का उपयोग करना चाहिए। लेकिन अन्य 95% अनुप्रयोगों के लिए, एक प्रबंधित कोड ढांचा काफी तेजी से होगा। आखिरकार C # को भी मशीन कोड में संकलित किया जाता है, और यदि आप चाहें तो इसे मूल से पूर्व-संकलित भी कर सकते हैं।
त्सही अशेर

2
वैसे, @RaidenCore, जिन ऐप्स का आपने पूर्ववर्ती C # उल्लेख किया है, इसीलिए वे C ++ में लिखे गए हैं। अगर आज वे लिखे जाते, तो कौन जानता है कि किस भाषा का इस्तेमाल किया जाता था। उदाहरण के लिए देखें।
त्सही अशर

1
जब आप RaisePropertyWPF में चाहते हैं तो यह वास्तव में उपयोगी है ! RaisePropertyChanged (nameof (संपत्ति)) का उपयोग RaisePropertyChanged ("संपत्ति") के बजाय करें
पियरे

17

लैम्ब्डा एक्सप्रेशन से इसे निकालने के लिए एक जानी-मानी हैक है (यह प्रॉपर्टी ऑबजर्वर क्लास से है, जोश स्मिथ ने अपने MVVM फाउंडेशन में):

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

क्षमा करें, यह कुछ संदर्भ याद कर रहा था। यह एक बड़े वर्ग का हिस्सा था जहां TPropertySourceसंपत्ति वाला वर्ग है। आप फ़ंक्शन को TPropertySource में कक्षा से निकालने के लिए सामान्य बना सकते हैं। मैं MVVM फाउंडेशन से पूर्ण कोड पर एक नज़र डालने की सलाह देता हूं ।


फ़ंक्शन को कॉल करने के तरीके के एक उदाहरण के साथ, यह निश्चित रूप से एक +1 है। उफ़, यह नहीं देखा कि डिबग दावे में एक है - इसीलिए एक डेवलपर को एक लाइन के महत्वपूर्ण हिस्से पर पहुंचने के लिए क्षैतिज रूप से स्क्रॉल करना बुराई है;)
ओरेगॉनहोस्ट

हम्म् ... मुझे इसे समझने के लिए इसे अलग करना होगा।
जिम सी

दृश्य स्टूडियो 2008 झंडे "TPropertySource" त्रुटि के रूप में ("पाया नहीं जा सकता")।
जिम सी

मुझे बस इसका एक प्रकार का नाम एहसास हुआ न कि केवल एक प्रतीक <T> जैसा कि C ++ में। TPropertySource क्या दर्शाता है?
जिम सी

2
इस संकलन को बनाने के लिए आप सिर्फ पढ़ने के लिए विधि हस्ताक्षर को बदल सकते हैं, public static string GetPropertyName<TPropertySource>(Expression<Func<TPropertySource, object>> expression)तो इस तरह कॉल करें:var name = GetPropertyName<TestClass>(x => x.Foo);
dav_i

16

ठीक है, यहाँ मैंने क्या बनाया है (मेरे द्वारा चुने गए उत्तर और उसके द्वारा संदर्भित प्रश्न के आधार पर):

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

उपयोग:

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

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

8

PropertyInfo वर्ग आप इस लक्ष्य को हासिल है, अगर मैं सही ढंग से समझ मदद करनी चाहिए।

  1. Type.GetProperties () विधि

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

क्या यही तुम्हें चाहिए था?


नहींं, हालाँकि मैं GetProperties का उपयोग करता हूं, जब एप्लिकेशन को "SomeSecret" के लिए अनुरोध प्राप्त होता है। यह ऐप मैप में "SomeSecret" को खोजता है ताकि यह पता चल सके कि "SomeClass" नामक एक वर्ग में "SomeProperty" नामक संपत्ति खोजने की आवश्यकता है।
जिम सी

nameof (SomeProperty) वास्तव में इसे .net 4.0 से आगे बढ़ाता है। ऐसे लंबे हैक की कोई आवश्यकता नहीं है।
दिव्य तिवारी

6

आप गुणों के वास्तविक नाम प्राप्त करने के लिए परावर्तन का उपयोग कर सकते हैं।

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

यदि आपको किसी संपत्ति को "स्ट्रिंग नाम" निर्दिष्ट करने का एक तरीका चाहिए, तो आप एक विशेषता क्यों नहीं लिखते हैं जिसे आप स्ट्रिंग नाम प्राप्त करने के लिए प्रतिबिंबित कर सकते हैं?

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

1
हां, यह है कि ऐप "SomeSecret" के लिए आने वाले अनुरोधों को कैसे संभालता है, लेकिन यह मुझे एक्सपोज़प्रॉपर्टी समस्या के लिए एक उपकरण नहीं देता है।
जिम सी

दिलचस्प ... तब आप MyProperty का नाम बदलकर अपने दिल की सामग्री तक ले जा सकते हैं जब तक आप MyStringName के साथ गड़बड़ नहीं करते हैं, और यदि किसी कारण से आप इसे बदलना चाहते हैं, तो आपको एक्सपोज़प्रॉपरि पेम को संशोधित करने की आवश्यकता है। कम से कम मैं इस तरह की चेतावनी के साथ विशेषता के बगल में एक टिप्पणी जोड़ सकता हूं क्योंकि आपको विशेषता के मूल्य को बदलने के लिए इसे देखना होगा (संपत्ति का नाम बदलने के विपरीत, जिसे किसी भी संदर्भ स्थान से किया जा सकता है)।
जिम सी

6

मैंने कई गुणों पर श्रृंखला के लिए आपके समाधान को संशोधित किया:

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

उपयोग:

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

4

उत्तर के आधार पर जो पहले से ही प्रश्न और इस लेख पर है: https://handcraftsman.wordpress.com/2008/11/11/how-to-get-c-property-names-without-magic-strings/ I इस समस्या का हल प्रस्तुत कर रहा हूँ:

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

और एक परीक्षण जो उदाहरण और स्थिर गुणों के लिए उपयोग दिखाता है:

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

3

पुराना सवाल है, लेकिन इस सवाल का एक और जवाब है कि हेल्पर क्लास में एक स्टेटिक फंक्शन बनाना है जो CallerMemberNameAttribute का उपयोग करता है।

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

और फिर इसका उपयोग करें जैसे:

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

0

आप वर्तमान फ़ंक्शन का नाम पाने के लिए स्टैकट्रेस क्लास का उपयोग कर सकते हैं, (या यदि आप किसी फ़ंक्शन में कोड डालते हैं, तो एक स्तर नीचे ले जाएं और कॉलिंग फ़ंक्शन प्राप्त करें)।

Http://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace(VS.71).aspx देखें


मुझे नहीं पता कि स्टैक ट्रेस पर कब्जा करने के लिए आपके पास कहां था, लेकिन मैं उस संपत्ति के नाम पर एक के बारे में नहीं सोच सकता।
जिम सी

आप ऐसा कर सकते हैं, लेकिन यह कंपाइलर इनलाइनिंग ऑप्टिमाइज़ेशन के कारण अप्रत्याशित परिणाम (अपवादों सहित) को जन्म दे सकता है। smelser.net/blog/post/2008/11/27/…
जोजेकी

0

मैं इस उत्तर का बड़े प्रभाव से उपयोग कर रहा हूं: एक अभिव्यक्ति के रूप में संपत्ति प्राप्त करें, एक स्ट्रिंग के रूप में, <Func <TModel, TPPperty >>

मुझे एहसास है कि मैंने पहले ही इस सवाल का जवाब कुछ समय पहले दिया था। मेरे अन्य उत्तर का एकमात्र लाभ यह है कि यह स्थैतिक गुणों के लिए काम करता है। मुझे इस उत्तर में वाक्यविन्यास बहुत अधिक उपयोगी लगता है क्योंकि आपको उस प्रकार का वैरिएबल बनाने की आवश्यकता नहीं है जिसे आप प्रतिबिंबित करना चाहते हैं।


0

मुझे अपने विशिष्ट उपयोग मामले के लिए पहले से सुझाए गए समाधानों का उपयोग करने में कुछ कठिनाई हुई, लेकिन अंततः इसका पता लगा लिया। मुझे नहीं लगता कि मेरा विशिष्ट मामला एक नए प्रश्न के योग्य है, इसलिए मैं अपना समाधान यहां संदर्भ के लिए पोस्ट कर रहा हूं। (यह प्रश्न से बहुत निकटता से संबंधित है और किसी अन्य के लिए एक समान मामले के साथ समाधान प्रदान करता है)।

मेरे द्वारा समाप्त किया गया कोड इस तरह दिखता है:

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

मेरे लिए महत्वपूर्ण हिस्सा यह है कि CompanyControlकक्षा में कंपाइलर मुझे केवल एक बूलियन संपत्ति चुनने की अनुमति देगा, ICompanyViewModelजिससे अन्य डेवलपर्स के लिए इसे सही करना आसान हो जाए।

मेरे समाधान और स्वीकृत उत्तर के बीच मुख्य अंतर यह है कि मेरी कक्षा सामान्य है और मैं केवल सामान्य प्रकार के बूलियन से गुणों का मिलान करना चाहता हूं।


0

यह मैंने इसे कैसे लागू किया है, इसके पीछे का कारण यह है कि जिस वर्ग से आप नाम प्राप्त करना चाहते हैं, वह स्थिर नहीं है, तो आपको उस का एक उदाहरण बनाने और फिर सदस्य का नाम प्राप्त करने की आवश्यकता है। तो यहाँ सामान्य मदद करने के लिए आता है

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

उपयोग इस तरह है

var label = ClassExtension.GetName<SomeClass>(x => x.Label); //x is refering to 'SomeClass'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.