- Home /
How to create instance of ScriptableObject and pass its constructor a parameter?
The only way to create an instance of a ScriptableObject seems to be:
ScriptableObject.CreateInstance("MyScriptableObject");
It is possible to give parameters while I'm creating the instance so that the constructor of my ScriptableObject class can initialise the instance using those particular parameters?
At the moment, I'm having to make do with creating the ScriptableObject instances using "new" (i.e. as if they were standard objects) but I'm getting warnings about doing this in the console which annoys me.
I know that I could directly set the values for properties of my instances once they've been created:
MyScriptableObject someInstance = ScriptableObject.CreateInstance("MyScriptableObject");
someInstance.intVariable = 5
but this just feels messy & wrong... I'm hoping that there's an alternative?
Edit/Update 4th Oct '13 Thanks for the replies all, in particular Kryptos for explaining why things are the way that they are. I would have voted you the right answer but I really like HanClinto's solution/answer and it's perfect for my needs... I don't know why I didn't think of it earlier :S
Thanks once again all - the info is very much appreciated!
perhaps it would feel less wrong to call a function that initializes everything?
Answer by HanClinto · Oct 04, 2013 at 04:16 PM
I concur with the other answers -- having a parameterless constructor is very valuable, in that the order of instantiation cleans up a LOT of potential headaches when serializing / deserializing objects.
However, to add something new, if you want to do a similar thing like what you're talking about, instead of setting individual parameters after instantiation (I agree, that's very messy with a lot of parameters), I would recommend creating an init() method that you pass all of your initialization parameters into.
So (in C#) this would look something like:
MyScriptableObject someInstance = ScriptableObject.CreateInstance("MyScriptableObject") as MyScriptableObject;
someInstance.init (5, "Gorlock", 15, owningMap, someOtherParameter);
It's 2 lines of code instead of 1, but it lets you keep the best of both worlds for parameterless constructors for serialization, and it lets you initialize your object in one clean line, at one clear point in time.
In order to make refactoring easier I would rather use typeof(...) ins$$anonymous$$d of a string:
$$anonymous$$yScriptableObject someInstance = ScriptableObject.CreateInstance(typeof($$anonymous$$yScriptableObject)) as $$anonymous$$yScriptableObject;
How are you doing that? Unity uses C# 4 and wont allow that...
What do you mean? This would be valid "C# 1" code. (if Unity already existed at that time ^^).Though the generic version is actually the more compact way and less error prone. Using "typeof" and a cast you have to use the type twice. So it's a potential problem when during manual refactoring you might change the type but forgot the other. The generic CreateInstance<T>
doesn't require a seperate cast.
Shorter:
$$anonymous$$yScriptableObject obj = ScriptableObject.CreateInstance<$$anonymous$$yScriptableObject>();
I believe this is right too...
$$anonymous$$yScriptableObject obj = ScriptableObject.CreateInstance<$$anonymous$$yScriptableObject>().init (5, "$$anonymous$$lock", 15, owning$$anonymous$$ap, someOtherParameter);
Yes, this is usually one of my favourite solutions, but keep in $$anonymous$$d in order for this to work your "init" method has to return it's own instance. So you need a return this;
at the end. (btw: your init method should be PascalCase and start with a capital letter).
Answer by vexe · Dec 21, 2013 at 02:52 PM
I would like to add another answer - a solution that I found to be a very elegant. Full credits go to @Jamora.
The idea is to use a Factory method. A method that is responsible for creating you the object you want, with the inputs you like.
public class PlayerData : ScriptableObject
{
private string name;
private float damage;
private int id;
public void Init(string name, float damage, int id)
{
this.name = name;
this.damage = damage;
this.id = id;
}
public static PlayerData CreateInstance(string name, float damage, int id)
{
var data = ScriptableObject.CreateInstance<PlayerData>();
data.Init(name, damage, id);
return data;
}
}
Usage:
PlayerData data = PlayerData.CreateInstance("nitex", 55.8f, 11);
This is a nice abstraction, but I wonder if it has any overhead when these scriptable objects get serialized? I imagine unity's serialization is smart enough to remove all methods before serialization, but I wonder if there is any overhead associated with that.
Excellent! I read the question and literally thought “factory method would be perfect.” I’m pleased to see another $$anonymous$$d provide this answer! It’s great because Unity controls constructors, and a factory pattern allows you to define one anyways. :)
My refinement would be to remove the “Init” function and set values directly, since I suspect it’s unlikely there are any other consumers of that function except the factory function. Personally, I like to call my factory methods “Of” so the code reads a little nicer, but that’s a matter of taste (just sharing nicely).
@kthrose I cannot overstate how tiny the memory footprint this technique produces. If you want to know more, I recommend “Game Engine Architecture:3rd edition” where it talks about assemblies, resulting images, and game memory space allocation.
Factories are great when used appropriately!
If you're creating the factory method in the same class you don't even need the init method. Remember that private is a class scope, so any code inside that class be it static or accessing multiple instances of the same class passed in via parameters can access every instance's private members.
Private does not restrict access to instance methods accessing members of its own instance (a distinction many devs seem to get wrong). It only cares about where the declaring code originates from. So you can simply write it a bit like you would a regular constructor:
public class PlayerData : ScriptableObject
{
private string name;
private float damage;
private int id;
public static PlayerData Create(string name, float damage, int id)
{
var data = ScriptableObject.CreateInstance<PlayerData>();
data.name = name;
data.damage = damage;
data.id = id;
return data;
}
}
Likewise, the following has always been valid in c#:
public class Foo
{
private string bar;
public static void SetAllBars(List<Foo> foos, string newBar)
{
foreach(var item in foos)
{
item.bar = newBar;
}
}
}
Answer by shavais · Oct 05, 2013 at 07:30 AM
Here's a proposed refinement of HanClinto's response:
MyScriptableObject someInstance = MyScriptableObject.Create(
new MyScriptableObjectConfig(){
level = 5,
name = "Gorlock",
age = 15,
map = owningMap
}
);
Here, the Create function is a public static shortcut function like this:
public static MyScriptableObject Create(MyScriptableObjectConfig config){
return MyScriptableObject.CreateInstance<MyScriptableObject>().Init(config);
}
public MyScriptableObject Init(MyScriptableObjectConfig config){
..
return this;
}
This way of doing it has some advantages:
the creation parameters are named, so we don't have to rely on intelisenseless to remind us of what they are
support for more (optional) creation parameters can be added for other possible use cases without changing this code at all
only one Init function and one Create function is needed, regardless of how many optional initialization parameters are eventually supported
the properties of the config object can be types that have explicit or implicit conversions defined for the various potential use cases, allowing the initialization code and the consumption code (above) to be free of having to deal with those kinds of concerns
Note that this code assumes that if CreateInstance() didn't produce an instance, some sort of exception was (or should be) raised, rather than null being passed back. If the failure of the creation of the instance is a possibility that shouldn't be an exception, then this code will need to be modified. (But so would HanClinto's, despite its use of 'as'.)
If the object isn't intended to be involved in the effort to persist things (and therefore doesn't need to support serialization) this alternative could be used:
MyObject someInstance = new MyObject(new MyObjectConfig(){
.
.
});
.. thereby supporting the use of readonly properties (that can only be set during construction) without fear of ending up proliferating constructor parameters, constructor overloads, etc. If MyObject derives from ScriptableObject, you'll get a warning about using the constructor, probably because of the serialization issue, but it doesn't seem to cause any problem if you never serialize or deserialize.
By the way, you can create objects of your own classes that don't derive from ScriptableObject at all. All you have to do is put them in a file of the same name as the class and it'll be globally accessible. (The class's config class will be accessible in any file that you use the class in.)
The definition for the config struct or class can be right above the definition for the object class. It can be as simple as a list of public variables, or as complex as needed to support whatever default values, parameter conversions, et etc. might eventually be desired.
The Create function can be put into a base class, the config object parameter to it can be made nullable, so then, in the case where the defaults are acceptable..
MyScriptableObject someInstance = MyScriptableObject.Create(null);
or
MyObject someInstance = new MyObject(null);
.. if the default parameters are obvious enough and serialization is not required. And/or if you feel like it, you can create a single default constructor that passes a default constructed MyObjectConfig to the main constructor. Then you can do this:
MyObject someInstance = new MyObject();
and still never have to worry about ending up with a mass of constructor overloads and explicit constructor parameters.
There are a lot of ways to attack the beast in C#. Not every class is concerned with serialization, in fact separating out the concern of persisting things is a good practice. Passing parameters to constructors can result in less code to create and maintain, and it doesn't have to end up causing problems. Just don't let yourself end up with a ton of constructor parameters or overloaded constructors; it's easy enough to avoid. And don't pass parameters to constructors that are going to end up needing to be serialized/deserialized. You don't serialize things like file handles or database connections or request contexts. Under particular circumstances, it may be ok to pass some things like that as optional constructor parameters even to objects that need to support serialization, if they have defaults that can be used in situations where serialization is going on.
Hi! Can you show how to apply values provided by config to a creating object? I don't understand what I should write in Init method to assign all values of config data to all variables of $$anonymous$$yObject class. Please share an example.
Answer by Kryptos · Aug 31, 2012 at 08:23 AM
this just feels messy & wrong
Actually, this is the good way to do it. Design patterns and good programming practices tell us that a constructor should only contruct the object, i.e. allocate the memory needed. Anything related to the goal/function of the object should be set afterwards.
There a lot of reason to do it that way, the first one is readibility to help code maintenance.
ScriptableObject does not escape this rule. And it uses a factory method (CreateInstance) to enforce this rule. The constructor is hidden and will juste create the asset. Any property would be set afterwards.
edit (2013/10/04)
Another reason is that ScriptableObject is a Serializable class, therefore it must have a parameterless constructor. Given this rule, any parameter to an additional constructor is only optionnal. Therefore it is better to enforce this rule by providing no such constructor.
Im sorry but if this indeed was the way to do it, then Unity wont use it in their own classes (e.g. new Color(1,1,1) and a hell lot of other. Having constructor with arguments I find extremely helpfull and usefull
Yeah, I don't agree with this either. To me the part of RAII that is still relevant in C# is exactly this part - the part that $$anonymous$$imizes how much code I have to write and maintain in order to consume an object. Using 4 constructor arguments is less self-documenting than writing 4 lines of subsequent code setting named properties, that's true, but with modern IDE's you can hover over a constructor to see what the argument names are, if you need to, or click on it and hit a key to see the constructor itself, and 1 line of terse code is a lot easier to create and maintain than 5 lines of verbose code. Especially if there's any complexity to the code required to come up with the appropriate values for things that you need to set at initialization time. If I'm unable to pass constructor arguments, I'm writing a wrapper class or a static function call I can make that will construct the thing using passed in parameters. I'm not going to write 5 lines of verbose code every time I consume the thing.
Color is not a good example since it is not a class but a struct (same with Quaternion and Vector).
But for example you cannot do new Component()
but need to use AddComponent()
. So yes even Unity use it for its own calsses.
Parameterless constructors are generally superior. There are few examples where it's a good idea, Vector, Color, String, these are all fine as the behavior of the parameters is intuitive and likely to never change. Some of the worst bugs I've seen, and difficult to maintain/refactor code, has come from this idea of packing parameters into constructors, especially with use of default values. I've seen classes with 20 parameter constructors, and 10+ versions of the constructors, wildly ugly, bug spawning messes that nobody wants to fix so they persist in the code forever. Use constructor parameters VERY sparingly, as it becomes decidedly less clean as your code evolves.
To be fair, most of what's discussed in these comments was developed that way because it's the path of least resistance, regarding ScriptableObject and Component creation.
$$anonymous$$ryptos - Whether theyre classes or structs is irrelevant. They are bunches of data you can call functions on and pass around, they have slight differences but none of them are important for this issue.
The reason you have to use AddComponent is so that Unity can guarantee that you're calling it on an existing game object ins$$anonymous$$d of calling new Component(null), which would just need to waste processing power null checking every time you create a new component and throwing an exception ins$$anonymous$$d of just not compiling.
REIam - Having a constructor with 20 parameters is no more bad practice and no more likely to cause bugs than having any other function with 20 parameters. The same applies to having 10+ overloads of any function. If you're advocating parameterless constructors, you might as well advocate parameterless functions as well.
Another point that no one has mentioned is the use of readonly variables. A readonly variable can only be assigned in the constructor. So you can have a public readonly variable and you don't have to worry about other classes fiddling with it, or even other functions in the same class for that matter, which I find very useful.
Answer by triangle4studios · Jan 04, 2021 at 05:10 AM
The absolute best and ONLY way to properly instantiate a scriptable:
public MyScriptableObject obj; // Pass in the ACTUAL scriptable by ref or in the inspector
void Init(){
obj = ScriptableObject.Instantiate(obj);
}
This creates a physical clone of the object without affecting the original. This is how scriptables are meant to be used.
First time I didn't regret going to the second page of Unity Answers. This is the most simple and correct way to do this. Thank you!
Your answer
![](https://koobas.hobune.stream/wayback/20220613080431im_/https://answers.unity.com/themes/thub/images/avi.jpg)