-1

I have the following: a base class SystemBody (which has 3 readonly fields that must be set in the contructor, and never get changed in the object's lifetime), arbitrary derived classes from SystemBody, and the following generic method:

public T AddBody<T>(SystemBody parentBody) where T : SystemBody, new()
{
    T rtn = new T(this, ++currentID, parentBody != null ? parentBody.id : -1);

Which results in:

error CS0417: 'T': cannot provide arguments when creating an instance of a variable type

I am struggling to understand what I'm intended to do in this situation.

SystemBody has a constructor with the signature required, but I have no way to enforce that a constructor with that signature exists in T. (C# seems to be noticeably lacking a generic type constraint for having a constructor with any arguments)

I can't use an initializer (which does work as expected if the properties are public) because they're readonly. (An initializer would be my preferred choice)

Using public int id {get; private set;} has identical results to public readonly int id;

The only solution I can think of is to add an Initialize method to the base class which takes the parameters I need to set - this feels like a gross hack that doesn't feel like it conforms to the way C# code should be written.

What am I missing? Do I just have to write Initialize?

StarManta
  • 1
  • 2
  • 2
    common design patterns for this problem are the [factory method](https://en.wikipedia.org/wiki/Factory_method_pattern) and the [abstract factory.](https://en.wikipedia.org/wiki/Abstract_factory_pattern) – Zohar Peled Jul 23 '20 at 06:02
  • if you restrict `T : SystemBody` do you think you could simply construct a `new SystemBody` ? because this restriction to T is already quite narrow. even if it would work, what would you do with a class that derives from `SystemBody` but has a slightly different constructor? – Mong Zhu Jul 23 '20 at 06:02
  • The way I deal with this is to define a `Dictionary` and then stick in there all of the types that `T` can be with a `Func` to create your instance. – Enigmativity Aug 10 '20 at 01:41

1 Answers1

0

From the docs:

where T : new() The type argument must have a public parameterless constructor. When used together with other constraints, the new() constraint must be specified last. The new() constraint can't be combined with the struct and unmanaged constraints.

So basically you can't.

You will need to either to change the properties to be not readonly:

new T() { SomeProperty = blah}

or use:

(T)Activator.CreateInstance(typeof(T), args)

or use a Func to initialize it.

halfer
  • 19,824
  • 17
  • 99
  • 186
TheGeneral
  • 79,002
  • 9
  • 103
  • 141