8

I found a post with a great answer for a problem I have, but I can't seem to find a small detail I'm looking for.

public class myModel
{
   [JsonProperty(PropertyName = "id")]
   public long ID { get; set; }
   [JsonProperty(PropertyName = "some_string")]
   public string SomeString {get; set;} 
}

I need a method which returns the JsonProperty PropertyName of a specific property. Maybe something where I can pass the Type and the Property I need, and the method returns the value if found.

Here's the method I found which has me in the right direction (I believe) taken from here

using System.Linq;
using System.Reflection;
using Newtonsoft.Json;
...

public static string GetFields(Type modelType)
{
    return string.Join(",",
        modelType.GetProperties()
                 .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>()
                 .Where(jp => jp != null)
                 .Select(jp => jp.PropertyName));
}

The goal is to call a function like this (any modification is fine)

string field = GetField(myModel, myModel.ID);

Update #1

I modified the above to this, but I don't know how to get the string of ID from myModel.ID.

public static string GetFields(Type modelType, string field) {
    return string.Join(",",
        modelType.GetProperties()
            .Where(p => p.Name == field)
            .Select(p => p.GetCustomAttribute<JsonPropertyAttribute>())
            .Where(jp => jp != null)
            .Select(jp => jp.PropertyName)
        );
}

I want to prevent hard-coding strings of actual property names. For example I do not want to call the above method as:

string field = GetField(myModel, "ID");

I would rather use something like

string field = GetField(myModel, myModel.ID.PropertyName);

But I'm not entirely sure how to properly do this.

Thanks!

RoLYroLLs
  • 3,113
  • 4
  • 38
  • 57
  • https://stackoverflow.com/questions/6637679/reflection-get-attribute-name-and-value-on-property – twoleggedhorse Aug 22 '17 at 20:00
  • It shouldn't matter that it's a json attribute, the above should still work – twoleggedhorse Aug 22 '17 at 20:01
  • 1
    Possible duplicate of [Reflection - get attribute name and value on property](https://stackoverflow.com/questions/6637679/reflection-get-attribute-name-and-value-on-property) – twoleggedhorse Aug 22 '17 at 20:02
  • @demo I got it to work with strings, but how do I get `ID` from `myModel.ID` i'm not familiar with `Reflection` if it even has anything to do with it. – RoLYroLLs Aug 22 '17 at 20:03
  • Possible duplicate of [Get property value from string using reflection in C#](https://stackoverflow.com/questions/1196991/get-property-value-from-string-using-reflection-in-c-sharp) – demo Aug 22 '17 at 20:03
  • @twoleggedhorse I think my problem is more in terms of how to prevent myself or other users from hard-coding a `string` to represent the property `myModel.ID` – RoLYroLLs Aug 22 '17 at 20:06
  • @demo see update #1, I kinda did that already, but how do I prevent hard-coding a string. I'd prefer to use something like `string field = GetField(myModel, myModel.ID.PropertyName());` I hope this helps understand my issues better – RoLYroLLs Aug 22 '17 at 20:10
  • what about this https://stackoverflow.com/a/35095504/3917754 ? – demo Aug 22 '17 at 20:27
  • @demo that's funny I was just looking at that one. But since this class is not static, how can I use something like this without instantiating an object? Is that even possible? Sorry for my ignorance. I guess I'm learning as I go here too. – RoLYroLLs Aug 22 '17 at 20:29

1 Answers1

9

Here's a way of doing it while keeping things strongly typed:

public static string GetPropertyAttribute<TType>(Expression<Func<TType, object>> property)
{
    var memberExpression = property.Body as MemberExpression;
    if(memberExpression == null)
        throw new ArgumentException("Expression must be a property");

    return memberExpression.Member
        .GetCustomAttribute<JsonPropertyAttribute>()
        .PropertyName;
}

And call it like this:

var result = GetPropertyAttribute<myModel>(t => t.SomeString);

You can make this a bit more generic, for example:

public static TAttribute GetPropertyAttribute<TType, TAttribute>(Expression<Func<TType, object>> property)
where TAttribute : Attribute
{
    var memberExpression = property.Body as MemberExpression;
    if(memberExpression == null)
        throw new ArgumentException("Expression must be a property");

    return memberExpression.Member
        .GetCustomAttribute<TAttribute>();
}

And now because the attribute is generic, you need to move the PropertyName call outside:

var attribute = GetPropertyAttribute<myModel, JsonPropertyAttribute>(t => t.SomeString);
var result = attribute.PropertyName;
DavidG
  • 113,891
  • 12
  • 217
  • 223
  • You are awesome! I had just found a very similar answer that gave me the `MemberExpression` and stuff. Thank you. It works as desired. – RoLYroLLs Aug 22 '17 at 20:41
  • I've simplified it, dunno why I didn't do it this way in the first place! – DavidG Aug 22 '17 at 20:50
  • nice! Thanks! I see you can from a VB6 background like me =) I was away during the .Net intro era, and sometimes I wish I knew so much more than I I think I do. =) – RoLYroLLs Aug 22 '17 at 20:52
  • thanks for the `null` checking, I was just about to mention it. – RoLYroLLs Aug 22 '17 at 20:54
  • DavidG, for future things I may need/use, how can I make `JSonPropertyAttribute` a generic type that I can pass to the method? – RoLYroLLs Aug 22 '17 at 21:12
  • David, I just ran this against my class and it errors out with `null exception` when a property does not have a `JsonPropertyAttribute` – RoLYroLLs Aug 22 '17 at 21:17
  • The generic version in the edit would help with that. Check if the return from this is `null`. Or even use null propogation check: `var result = GetPropertyAttribute(..)?.PropertyName;` – DavidG Aug 22 '17 at 21:17
  • thanks! changed it a bit for my liking but works great! – RoLYroLLs Aug 22 '17 at 21:26
  • Minor improvement with pattern matching: `if (!(property.Body is MemberExpression memberExpression)) throw new ArgumentException("Expression must be a property");` – Phil B Oct 19 '20 at 18:06
  • Hmm not sure why but this example didn't work for me for property types others than string. – cah1r Oct 17 '22 at 10:19