Im trying to create a generic function that can take anything inherited from a base class " NodeBase" and generate a grid. I cant seem to provide arguments when creating an instance of a variable type.
public T[,] CreateGridT<T>(T node, T[,] grid ) where T : NodeBase, new()
{
grid = new T[gridSizeX, gridSizeY];
Vector3 worldBottomLeft = transform.position - Vector3.right * gridWorldSize.x / 2 - Vector3.forward * gridWorldSize.y / 2;
for (int x = 0; x < gridSizeX; x++) {
for (int y = 0; y < gridSizeY; y++) {
Vector3 worldPoint = worldBottomLeft + Vector3.right * (x * nodeDiameter + nodeRadius) + Vector3.forward * (y * nodeDiameter + nodeRadius);
grid [x, y] = new T (worldPoint, x, y);
}
}
return grid;
}
Line 10 Errors:
grid [x, y] = new T (worldPoint, x, y); Errors `T’: cannot provide arguments when creating an instance of a variable type
Please help is there a way around this
In your first line, you’ve specified that T must have a constructor with no parameters (“new()”).
In line 10, you then use a constructor that has 3 parameters. The generic function can’t be sure that that constructor exists, because that’s not what you specified.
You should be able to fix it by changing “new()” in the first line to “new(Vector3, int, int)”, I think.
Ok tried your suggestion but its not liking it : Unexpected symbol Vector3', expecting
)’ …
Here is my base node class incase I screwed up anything
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NodeBase {
private NodeAttributeBase _nodeAttributes;
public NodeAttributeBase nodeAttributes{get {return _nodeAttributes;}}
public NodeBase(Vector3 _worldPosition, int _gridX, int _gridY) {
_nodeAttributes.worldPosition = _worldPosition;
_nodeAttributes.gridX = _gridX;
_nodeAttributes.gridY = _gridY;
}
}
[code/]
Use System.Activator.CreateInstance(Type type, params object[ ] args).
grid [x, y] = System.Activator.CreateInstance(typeof(T), worldPoint, x, y) as T;
1 Like
Perfect will give it a go, thanks heaps guys
You shouldn’t need Activator since you’re specifying the base type for T in your constraint. If NodeBase has a constructor that takes 3 arguments then just get rid of the new() constraint entirely. Unless NodeBase is an interface in which case you’re still making assumptions about how implementing classes construct themselves.
Long and short of it - why is new() there in the first place?
You can’t specify that much about a generic type’s constructors. The only allowable constraint is “new()” which specifies that the type must have a default constructor.
If you need to create instances of T in your generic method, new() is the only constraint which enables you to use the “new” keyword, though, as you found out, it doesn’t allow you to use any arbitrary constructor. It only enables the default constructor “new T()”.
Here are three ideas to work around your problem:
- New up your T with the default constructor and then set the properties via an initializer
- Use an abstract factory which creates T’s of type NodeBase based on a switch-like statement
- Use the System.Activator class which allows you create objects of types only known at runtime
Of these options, only #1 really requires the new() constraint, so you can probably remove it if you’re going with the Activator.
AFAIK, the System.Activator is the only way to create an arbitrary type without an ugly if/then or switch block. It’s not free however, since it uses reflection which comes with a performance penalty.
2 Likes