-1

I have a class that contains multiple string fields. Whenever an object of this class is instantiated, I'd like those fields to be automatically assigned with the same specific default value (something like "Undefined"). The reason is:

  • If I have to serialize the object before all fields are populated with real data, I want those fields to display as this default value rather than being null or string.Empty.

  • String fields may be added/removed from this class as the project progresses. I'd like to not have to touch the constructor every time that occurs.

Is there any way to do this other than explicitly assigning the default value to each of the string fields one by one in the class constructor?

Mike Bruno
  • 600
  • 2
  • 9
  • 26
  • is it in winforms ? – Software Dev Mar 29 '18 at 20:57
  • And by string, do u mean string variable or `textbox` ? – Software Dev Mar 29 '18 at 20:58
  • Usually, for me, these classes live in a class library. Not specific to winforms – Mike Bruno Mar 29 '18 at 20:58
  • so u mean ur class has `public string abc` and many more declared as the same ? ?? – Software Dev Mar 29 '18 at 20:59
  • I am not sure i am following you. Are you asking for how to do something like `public int MyField = 42;`? –  Mar 29 '18 at 21:00
  • field: `private string _value = "UNDEFINED";`? property (c#6): `public string Value { get; } = "UNDEFINED";`? – NtFreX Mar 29 '18 at 21:00
  • what you can do is create a class level string variable and then just bind each string with that string variable, you want me to post an answer for that ? i'll be glad to post one :) – Software Dev Mar 29 '18 at 21:02
  • The short answer is that there isn't an easy efficient way of checking all of your fields. The simplest way is to define your defaults as const for the various data types you will have, and then assign each variable a default, either in auto-initializer as shown in an example or simply in the definition of the field. You can even put your const defaults into a static class so that they are the same across all of your classes. But, again, you'll need to write the definition or auto-intializer correctly or values could still be missing. – user7396598 Mar 29 '18 at 21:16
  • It would be awesome if you could share a [mcve] showing your existing code, so we can see the kind of duplication you are trying to avoid. – mjwills Mar 29 '18 at 21:22

9 Answers9

2

In C# 6.0 and above, you can use Auto-Property Initializer:

https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-6#auto-property-initializers

Basically:

public string Property { get; set; } = "UNDEFINED";
GBreen12
  • 1,832
  • 2
  • 20
  • 38
  • 1
    How does this even answer OP's question ? – Software Dev Mar 29 '18 at 21:01
  • Maybe I don't understand the question but it seems like he's basically asking if he has a type, how to get properties to have default values. The question is not very clear so I may be wrong. – GBreen12 Mar 29 '18 at 21:04
  • This is in fact what the OP should do...I also suggested putting his default values into a static class to ensure the default string for each class is the same. – user7396598 Mar 29 '18 at 21:18
  • What the OP wants is **not** to have to do this. He wants to automatically set all the string properties to a value without having to do anything. I know, funny... :-) – JuanR Mar 29 '18 at 21:23
2

You would have to use reflection. Something like this

Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();

foreach (PropertyInfo property in properties)
{
    if (property.PropertyType == typeof(string)) property.setValue(obj, "UNDEFINED");
}
Zexks Marquise
  • 1,497
  • 14
  • 18
1

First of all: I don't see how it could be best practice to do what you want.

If you want something like this to show up in your code:

public string Property { get; set; } = "UNDEFINED";

You should probably look into creating custom snippets that simply write exactly that. e.g. https://msdn.microsoft.com/en-us/library/ms165394.aspx


If you don't want that, you could use reflection to find all fields (e.g. strings) in the constructor and set them.

C# Reflection - Get field values from a simple class

FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public | 
                                          BindingFlags.NonPublic | 
                                          BindingFlags.Instance);

Setting a property by reflection with a string value

Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Alex AIT
  • 17,361
  • 3
  • 36
  • 73
  • Reflection is the way to do it after the fact. But, you are creating quite a bit of overhead for little to no gain. Write your definitions or auto-inits correctly from the start. – user7396598 Mar 29 '18 at 21:16
  • Agreed, that is why I suggested the snippets. – Alex AIT Mar 29 '18 at 21:17
0

Well, why not have an extension method like

public static class MyClass
{
  public static string GetDefault(this str, string defaultVal)
 {
   return string.IsNullOrEmpty(str) ? defaultVal : str;
 }
}

For a type

public class SomeClass
{
  public string str = string.Empty;
}

You can call

SomeClass s = new SomeClass();
s.str.GetDefault("UNDEFINED");
Rahul
  • 76,197
  • 13
  • 71
  • 125
  • This would require me to remember to add a call to GetDefault() in the constructor for each string field in the class, right? That's what I'm hoping to avoid... – Mike Bruno Mar 29 '18 at 21:06
  • This is a way to check each field and get a default if it is currently null. It is not required to be in the constructor, but it would need to be called on each field at some point before you use the field, or the default will not be set. – user7396598 Mar 29 '18 at 21:21
0

You can initialize values to fields directly instead of in the constructor.

private string myStringVariable = "UNDEFINED";

Perhaps you should reconsider the structure of your program though if it permits many fields to be initialized to undefined.

Mike
  • 461
  • 4
  • 8
0

Maybe I am misunderstanding this but why not do word for word what you described in the question in your constructor?

    public class Weee
    {
        public string name { get; set; }
        public int order { get; set; }
        public string whatever { get; set; }

        public Weee()
        {
            foreach(var p in typeof(Weee).GetProperties().Where(a => a.PropertyType == typeof(string)))
            {
                p.SetValue(this, "wut");
            }
        }
    }
Travis Acton
  • 4,292
  • 2
  • 18
  • 30
0

You can create a property initializer and have a base class use it. Your classes can then inherit from the base and have their properties automatically initialized:

public class PropertyInitializer
{
    public void Initialize<T>(object obj, T value)
    {
        PropertyInfo[] properties = obj.GetType().GetProperties();
        foreach (PropertyInfo property in properties)
        {
            if (property.PropertyType == typeof(T))
            {
                property.SetValue(obj, value);
            }
        }
    }
}

public class InitializedBase
{
    protected InitializedBase()
    {
        var initializer = new PropertyInitializer();
        //Initialize all strings 
        initializer.Initialize<string>(this, "Juan");
        //Initialize all integers
        initializer.Initialize<int>(this, 31);
    }
}

//Sample class to illustrate
public class AutoInitializedClass : InitializedBase
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        return string.Format("My name is {0} and I am {1} years old", Name, Age);
    }
}

Sample usage:

AutoInitializedClass sample = new AutoInitializedClass();
Console.WriteLine(sample);

Console output:

My name is Juan and I am 31 years old

Notice the base class is using the PropertyInitializer class to initialize fields. This is a simplified example. You can expand it as it fits you (it may not work out of the box with all types).

I personally don't recommend this. It's called a constructor for a reason but you asked a question and I provided an answer.

JuanR
  • 7,405
  • 1
  • 19
  • 30
0

Here is a simple class from which you can inherit that does exactly what you want:

Example usage:

public class MyClass : DefaultedObject<string>
{
    public string MyStringField;
    protected override string Default => "UNDEFINED";
}

var myClass = new MyClass();
// myClass.MyStringField == "UNDEFINED"

Implementation:

public abstract class DefaultedObject<T>
{
    protected DefaultedObject()
    {
        T defaultValue = Default;
        FieldInfo[] fields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
        foreach(FieldInfo field in fields) {
            if(field.FieldType == typeof(T)) {
                field.SetValue(this, defaultValue);
            }
        }
    }

    protected abstract T Default { get; }
}
GregorMohorko
  • 2,739
  • 2
  • 22
  • 33
0

I appreciate all the feedback to this question. Here's what ended up working. First, for any string attributes in the class that I wanted to receive an automatic default value, I established as a property:

public string attribute1 {get; set;}
public string attribute2 {get; set;}

And so on. Then, in the class constructor, I included the following loop which iterates through each property of type string:

foreach(PropertyInfo property in GetType().GetProperties())
{
    if (property.PropertyType == typeof(string))
        property.SetValue(this, "UNDEFINED"));
}

This produced the desired outcome for me.

Mike Bruno
  • 600
  • 2
  • 9
  • 26