2

I have a user details class

public partial class UserDetails
    {
        public int? Level { get; set; }
        public string Unit { get; set; }
        public string Bio { get; set; }
        public bool? Gender { get; set; }
        public int? Mobile { get; set; }
        public string Photo { get; set; }
    }

I am writing an update method:

public bool UpdateDetails(string userId, UserProperties updateProperty, string value)
        {
         switch(updateProperty)
            {
                case UserProperties.Unit:
                    details.Unit = value;
                    break;
                case UserProperties.Photo:
                    details.Photo = value;
                    break;
                default:
                    throw new Exception("Unknown User Detail property");
            }

May I do something like dynamic property in JavaScript? e.g.

var details = new UserDetails();
details["Unit"] = value;

Update

As of year 2019! How about try to use this new feature?! DynamicObject DynamicObject.TrySetMember(SetMemberBinder, Object) Method

I am trying to figure out how to write it.

Franva
  • 6,565
  • 23
  • 79
  • 144
  • 1
    You can do it with reflection: https://stackoverflow.com/a/1197004/3891038 – Julio E. Rodríguez Cabañas Apr 26 '19 at 09:58
  • 1
    Reflection might do the trick, but I don't think you want to use that. – just-my-name Apr 26 '19 at 09:58
  • 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) – GSerg Apr 26 '19 at 09:59
  • Possible duplicate of [Setting a property by reflection with a string value](https://stackoverflow.com/questions/1089123/setting-a-property-by-reflection-with-a-string-value) – Liam Apr 26 '19 at 10:00
  • Aren't you looking for AutoMapper (https://github.com/AutoMapper/AutoMapper)? – BerDev Apr 26 '19 at 10:07
  • 1
    If you have hardcoded the string anyway, why not just `details.Unit` instead? – Lasse V. Karlsen Apr 26 '19 at 10:36
  • @LasseVågsætherKarlsen I am not using hardcoded strings, I am using enum. enum.ToString() is the way How I get the property string name. – Franva Apr 26 '19 at 14:13
  • @BerDev not looking for the mapper, as mapper just does mapping for all properties whereas I just want to update 1 specific property. – Franva Apr 26 '19 at 14:13
  • @just-my-name you are probably right, I have tried the new feature: DynamicObject.TrySetMember(), but it doesn't meet my requirement. So I will have to go down that path- reflection. After so many years, it's still the reflection that makes my day :) – Franva Apr 26 '19 at 14:16
  • @JulioE.RodríguezCabañas yep, reflection probably would be my choice – Franva Apr 26 '19 at 14:18
  • The DynamicObject link did not work for me when using EF/FromSQLRaw to dynamically create a custom class object at runtime. – AussieJoe Mar 12 '20 at 18:32

3 Answers3

5

You can do it via reflection for properties that exist on the object.

C# has a feature called Indexers. You could extend your code like this to allow for the behavior you are expecting.

 public partial class UserDetails
    {
        public int? Level { get; set; }
        public string Unit { get; set; }
        public string Bio { get; set; }
        public bool? Gender { get; set; }
        public int? Mobile { get; set; }
        public string Photo { get; set; }
         // Define the indexer to allow client code to use [] notation.
       public object this[string propertyName]
       {
          get { 
            PropertyInfo prop = this.GetType().GetProperty(propertyName);
            return prop.GetValue(this); 
          }
          set { 
            PropertyInfo prop = this.GetType().GetProperty(propertyName);
            prop.SetValue(this, value); 
          }
       }
    }

Other than that, if you don't know the properties at runtime, you can use the dynamic type.

Alen Genzić
  • 1,398
  • 10
  • 17
  • Hi Alen, thanks for this idea, I was thinking of Indexer, but it just moves the code I wrote in Switch to the Indexer, which is what I want to avoid. See my update for the new feature: DynamicObject.TrySetMember() – Franva Apr 26 '19 at 13:49
  • 1
    FYI, This did not work for me when using FromSQLRaw method. Properties never appear in the class, object is always null and void of any properties. – AussieJoe Mar 12 '20 at 18:31
3

If you don't want to use reflection you can slightly tweak Alens solution to use dictionary to store data.

public class UserDetails
{
    private Dictionary<string, object> Items { get; } = new Dictionary<string, object>();

    public object this[string propertyName]
    {
        get => Items.TryGetValue(propertyName, out object obj) ? obj : null;
        set => Items[propertyName] = value;
    }

    public int? Level
    {
        get => (int?)this["Level"];
        set => this["Level"] = value;
    }
}
just-my-name
  • 465
  • 1
  • 6
  • 15
  • 1
    Or you could extend the UserDetails class if you inherit the Dictionary class to eliminate the added redundant indexer "this". – Daniel C Apr 26 '19 at 10:45
  • @DanielC great idea :) – Franva Apr 26 '19 at 14:21
  • hi just, in my case I do not need to Getter as my model classes are generated from Entity Framework. All I need to do is to update a specific property on those generated Model Classes. – Franva Apr 26 '19 at 14:22
0

The closest thing would be the ExpandoObject:

https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=netframework-4.8

For example:

dynamic sampleObject = new ExpandoObject();
sampleObject.test = "Dynamic Property";
Console.WriteLine(sampleObject.test);
Metheny
  • 1,112
  • 1
  • 11
  • 23
  • hi Metheny, thanks for the idea, I actually had checked on it, it is used to dynamically build up an object which is not my case as my Model class has been generated by EF and cannot be changed. – Franva Apr 26 '19 at 14:19