6

C# 9.0 introduced init-only class properties feature but they can't be used when creating instances by class type with Activator.CreateInstance. A simplistic example:

class Person
{
    public string Name { get; init; }
}

void Test()
{
    Person person = (Person)Activator.CreateInstance(typeof(Person));
    person.Name = "Bob"; // Doesn't work
}

Looking for some solution other than using constructor arguments (too many of them).

Mikk L.
  • 161
  • 2
  • 9
  • In that particular code why would you use `Activator` anyway? Or rather: if you know the type then why use `Activator`, and if you don't know the type and are using reflection, how would you even attempt to set the property without reflection? – Charlieface Aug 08 '21 at 00:28
  • Does this answer your question? [In C#9, how do init-only properties differ from read-only properties?](https://stackoverflow.com/questions/64749277/in-c9-how-do-init-only-properties-differ-from-read-only-properties) and [What is difference between Init-Only and ReadOnly in C# 9?](https://stackoverflow.com/questions/62372422/what-is-difference-between-init-only-and-readonly-in-c-sharp-9) and [What does init mean in c# 9?](https://stackoverflow.com/questions/62228994/what-does-init-mean-in-c-sharp-9) –  Aug 08 '21 at 00:59
  • There is a solution down in the discussion indeed, but David gave straight answer. – Mikk L. Aug 09 '21 at 15:26

2 Answers2

5

Init properties are settable only in the following contexts:

  • During an object initializer
  • During a with expression initializer
  • Inside an instance constructor of the containing or derived type, on this or base
  • Inside the init accessor of any property, on this or base
  • Inside attribute usages with named parameters

In turn, Object Initialization is simply syntactic sugar to set the instance properties or fields without directly invoking the constructor, and essentially transforms from

Person person = new Person { Name = "Bob" };

to

Person person2 = new Person();
person2.Name = "test";
Person person = person;

When using Activator.CreateInstance, you bypass this syntactic sugar. That said, if you are already using Activator.CreateInstance, you are potentially comfortable taking additional reflection hits. You can simply call PropertyInfo.SetValue to set the values after object creation:

Person person = (Person)Activator.CreateInstance(typeof(Person));
    
person.GetType().GetProperty("Name").SetValue(person, "Bob");

Alternatively, you can create constructors and pass the values to the constructor.

David L
  • 32,885
  • 8
  • 62
  • 93
  • Reflection hit is okay. But it's interesting that this method allows setting the init-only property several times and at any time. – Mikk L. Aug 09 '21 at 15:25
  • 1
    Reflection allows you to modify something at runtime without any of the restrictions that are provided by the compiler. Init is a compiler concept, not an IL or runtime concept. As a result, once you are passed compilation, you can change the object state as much as you like. – David L Aug 09 '21 at 15:45
-3

Init should be initialized in the construction of the object and therefore you should initialize its value in the constructor. You can do it this way:

(Person)Activator.CreateInstance(typeof(Person), "Bob");

Note, you need to add an appropriate constructor.

class Person
{
    public Person(string name)
    {
        Name = name;
    }        

    public string Name { get; init; }
}
Misha Zaslavsky
  • 8,414
  • 11
  • 70
  • 116
  • This is one way, but as I wrote it's not preferred solution as there are many constructor arguments. – Mikk L. Aug 09 '21 at 15:22