-1

So, my wish is to have a constructor (or a method) That would set all my class properties to default values. I've got here so far:

class TestClass
{
    public enum MyEnum { En1, En2, En3}
    public string MyString { get; set; }
    public int MyInt { get; set; }
    public MyEnum MyEnums { get; set; }
    public TestClass()
    {
        var Properties = this.GetType().GetProperties();
        foreach (var Property in Properties)
        {
            Property.SetValue(this,default(Property.GetType()));
        }           
    }
}

I am getting this error: "'Property' is a variable but is used like a type" (CS0118). I know i could use struct for this purpose. But is it actually possible to do something like this? Or I would have to write for each property something like: MyString = default(string), MyInt = default(int)...?

Thanks for any advice :)

maccettura
  • 10,514
  • 3
  • 28
  • 35
Michal Dvořák
  • 197
  • 3
  • 10
  • 8
    What makes you think that the property is _not_ already set to the default value? Why do you think you need to write any custom code for this? Have you tried just instantiating a class _without_ your constructor logic to see what the values are? – maccettura Sep 07 '17 at 14:39
  • https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/default-values-table – Michał Turczyn Sep 07 '17 at 14:42

3 Answers3

0

Here's the problem:

default(Property.GetType())

The default operator wants you to give it a type, not an instance of the Type class. This works, for example:

var x = default(String);

But this doesn't:

var y = default(typeof(String));

You don't actually need to do what you're doing at all. Just leave the default values alone. The compiler has already taken care of it by the time your constructor executes. Indeed, the easiest way to get the default value of a property, in your particular case where all the properties are known not to be explicitly initialized, is to take whatever value it already has:

Property.SetValue(this, Property.GetValue(this));

That serves no purpose: "Make it what it already is". But that's what your code is trying to do, because the uninitialized value each property already has is the value you're hoping to assign to it.

It is a bad idea to add a lot of code that spins around, wastes time, and does absolutely nothing at all.

But if you did need to do this (and I can't overstress that you don't), you would do it by creating an uninitialized value of the correct type:

var type = Property.GetType();
var dflt = (type.IsValueType) 
               ? Activator.CreateInstance(type) 
               : null;
Property.SetValue(this, dflt);
  • That's exactly what i've been looking for! :) Thank you very much – Michal Dvořák Sep 07 '17 at 15:26
  • 1
    @MichalDvořák Which is? Did you understand why I said that what you're trying to do is completely redundant? – 15ee8f99-57ff-4f92-890c-b56153 Sep 07 '17 at 15:28
  • Aand, by the way, as we were talking about the default operator, Why wouldn't something like: var y = default(typeof(Property.GetType())) work? – Michal Dvořák Sep 07 '17 at 15:34
  • Yeah, this seems redundant, but was just wondering, if there's a way to loop through the properties of some class and set the values to something, which i could do generally for all types (that is, the default value of a type). Probably this is useless to do in Constructor, maybe i would like to have a method like 'void SetEverythingToDefault' after my class is a mess with lots of properties. I have no real use of this. – Michal Dvořák Sep 07 '17 at 15:36
  • @MichalDvořák An instance of the `Type` class is not a type. `typeof(String)` is the same as `"".GetType()`; it is very much not the same thing as `String`. `new String()` compiles; `new typeof(String)` doesn't compile. – 15ee8f99-57ff-4f92-890c-b56153 Sep 07 '17 at 15:38
  • Your hypothetical `void SetEverythingToDefault()` method would make a lot more sense than doing this in a constructor, certainly. As a rule in .NET you'd just create a new instance, but there are cases where the existing instance is referenced in many places, and it would be useful simply to reinitialize it. For that case you might write an attribute class that defines default values, and do it that way. Then you could do stuff like only reinitialize some particular subset of properties (something we actually do in production code at my job in some cases). – 15ee8f99-57ff-4f92-890c-b56153 Sep 07 '17 at 15:40
  • Further: `Typeof(Property.GetType())` won't compile. The `typeof` operator returns an instance of the `Type` class corresponding to a type. `typeof(string)` works, but `Property.GetType()` returns an instance of the `Type` class, which won't work as an operand to `typeof`. – 15ee8f99-57ff-4f92-890c-b56153 Sep 07 '17 at 15:42
0

This would be one way to let any property have a default value:

class TestClass
    {
        private string _myString = "default";
        public string MyString {
            get {
                return _myString;
            }

            set {
                _myString = value;
            }
        }
    }
Rikard Askelöf
  • 2,762
  • 4
  • 20
  • 24
0

So as others have mentioned you have a slippery slope as there are defaults already of system types. But if you are dead set on saying: "No I want string to default to something other than null and be empty!"(I actually worked for a guy that was kind of nuts about removing nulls to the point of insanity). I would do it in two parts, make it optional and inherit an abstract class that can be invoked on it's base constructor to use reflection to get all objects of a given type. In my example I use strings.

Base example:

public abstract class Base_Setter
{
  public Base_Setter() { }

  public Base_Setter(string overrideValue)
  {
    foreach (var property in GetType().GetProperties())
    {
      if(property.PropertyType == typeof(string))
      {
        property.SetValue(this, overrideValue);
      }
    }
  }
}

Implementation example:

public class Setter : Base_Setter
{
  public Setter() {}

  public Setter(string overrideValue) 
    : base(overrideValue)  { }

  public string Description { get; set; }
  public string Notes { get; set; }  
}

Example of usage:

static void Main(string[] args)
{
  Setter usesSetup = new Setter(String.Empty);
  Setter usesNone = new Setter();

  Console.ReadLine();
}

This would then set ALL objects of a given type to a certain setting you could choose. Or if you say: "That's all well and good but I want it hard coded to just do string empties", you could easily take out the argument and fix it or else make another base called 'AllStringEmptiesBase' or something similar. Again this is not always recommended but if you have a giant set of POCOs and want to with a giant brush stroke ensure they are all set to string empty, reflection may be easier than one at a time going through and updating all the constructors. Plus you can reuse this on multiple classes through inheritance.

djangojazz
  • 14,131
  • 10
  • 56
  • 94