-1

I have a class with a lot of properties (all Strings). I dynamically receive the name (and value) of a property to be set. Don't want to do a 100 if-then's to set the right variable. Would like to call something like:

Person.setVar(string propname,  string propvalue)

I have tried the following (based on my limited understanding through various posts here on SO):

using System;
using System.Reflection;

namespace MiscTest {
    public class Person {
        public string personName;
        public string personAge;

        public void SetVar(string propName, string propValue) {
            PropertyInfo propInfo = this.GetType().GetProperty(propName);
            propInfo.SetValue(this, propValue, null); //<--error here
        }
    }
}

However, keep running into this error ... something about Object reference not set:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.
   at MiscTest.Person.SetVar(String propName, String propValue) in C:\<long-path>\PropertyTest.cs:line 13

Any idea of what I might be doing wrong?

UPDATE: I have added the answer to this question -- which was provided by one of the commenters.

Gopal
  • 7
  • 4
  • Did you breakpoint in the function, and ensure that `propInfo` was not null? [Type.GetProperty](https://learn.microsoft.com/en-us/dotnet/api/system.type.getproperty?view=netcore-3.1#System_Type_GetProperty_System_String_) returns null if the property name was not found. – Sean Skelly Jun 30 '20 at 18:32
  • 2
    Also, `personName` and `personAge` are fields, not properties (no get; set;). You would need `FieldInfo`. Try this [SO Question](https://stackoverflow.com/q/12680341/3791245) for ideas. – Sean Skelly Jun 30 '20 at 18:34
  • @Sean Skelly ... You are correct. propInfo was coming as null. I had not understood the difference between fields and properties. I have it working now and will add the update to my code in my original post. Thanks a lot. – Gopal Jun 30 '20 at 20:28
  • Why would you want to do that? why not simply `obj.property = something` ? Also notice the difference between fields and properties – asaf92 Jul 01 '20 at 07:41

2 Answers2

0

Edit:

So after reading OP's answer to my question below, there are several issues here:

Why the code fails?

The reason the code fails is because personName and personAge are public fields and not properties, so you should probably use FieldInfo.

What's the difference between a field and a property?

A field is a variable that exists per class instance (per object). It can be modified directly by anyone who has access to that field (depending on the accessibility defined by public/protected/private keywords.

A property in C# can be thought of as a "getter" (and "setter" if defined) functions. Usually (but not always) they provide a layer of abstraction to some private field (also called "backing field"), in order to prevent anyone from modifying that field directly. Instead of having a GetAge() & SetAge(int age) methods, we can write:

private int _age
public int Age
{
    get
    {
        return _age;
    }
    set
    {
        _age = value;
    }
} 

Instead of writing this code we can simply write public int Age {get; set;} (also called auto-properties). this allows us to write code like if(somePerson.Age == 3) instead of if(somePerson.GetAge() == 3), and somePerson.Age = 4 instead of somePerson.SetAge(4). It's just a shortcut.

You might ask what's the point of getters and setters and why not simply have a public field and ignore all this non-sense, and the answer is that when you expose a field you have less control over how your class will be used. Let's say that I want a BarMitzvah event to be raised every time someone sets Person's age to 13, With properties I can change public int age {get; set;} to:

private int _age
public int Age
{
    get
    {
        return _age;
    }
    set
    {
        if(value == 13)
        {
            RaiseBarMitzvahEvent();
        }
        _age = value;
    }
} 

I can't do the same with a public field (unless I change it to a property)

What you should REALLY do

I don't know if you have the time or resources to refactor huge 100 fields large classes, but for the future when writing C# code you should:

  • Avoid large classes. Classes shouldn't contain 100 fields (private and definitely not public). You should probably break it to several classes, use composition and follow the Single Responsibility Principle.
  • When you want to dynamically set many data points, you probably want to use something like a dictionary rather than many different fields. It's especially true when all your properties are strings and you can simply use person.SomeDictionaryName[propName] = propValue.
  • Avoid public fields. In almost any case where you use a public field you can use auto-properties (which you should also avoid IMO but that's more subjective)
  • When you find yourself using reflection - there's usually a better way to go about what you're doing.

Original

Why not simply:

personInstance.personName = "Some Name";

Why do you need all the extra code and reflection non-sense when the fields are already public? Why have a SetVar function when you already can set "variables" (actually fields) by simply using the assignment operator (=)?

asaf92
  • 1,557
  • 1
  • 19
  • 30
  • Because there are almost a 100 fields in the class and the field/value to be set comes from elsewhere for which I have no control. Wanted to avoid stuff like: if (fieldname = "xyz") person.xyz = fieldvalue ... a 100 times. – Gopal Jul 20 '20 at 15:26
  • OK I understand your problem. It sounds like it's just bad design, you're trying to introduce some sort of duck-typing to C# which is a static language. I'll edit my answer to answer more thoroughly because there are several problems here – asaf92 Jul 20 '20 at 18:02
  • I answered your question now with explanations on fields vs properties as well as some extra tips – asaf92 Jul 20 '20 at 18:41
-2

Based on Sean Kelly's suggestion: The class members are fields (not properties) and hence I need to get FieldInfo and not GetProperties. So after changing the code to:

    public void SetVar(string propName, string propValue){
        FieldInfo fieldInfo = this.GetType().GetField(propName);
        fieldInfo.SetValue(this, propValue);
    }

It now Works!

Gopal
  • 7
  • 4
  • Great! Glad it worked. You can also mark your own answer as accepted, though [per StackOverflow](https://stackoverflow.com/help/self-answer#:~:text=Yes!,to%20answer%20their%20own%20questions.&text=Alternatively%2C%20you%20may%20go%20back,48%20hours%20to%20do%20so.), you need to wait 48 hours to do so, in case someone else comes along and provides an answer you like better. – Sean Skelly Jun 30 '20 at 20:39
  • Lastly, per the link I posted in the comment to your question, I suggest you have your code handle both fields _and_ properties, so that your `SetVar` method is flexible for the future. You or someone else may come along and add a property to this class, forgetting that `SetVar` only handles fields. – Sean Skelly Jun 30 '20 at 20:41
  • Good suggestion. Will do. – Gopal Jun 30 '20 at 20:45