I have two base classes BaseObject
and BaseObjectSettings
. The first defines the object behaviour and the second defines the state of the class (useful for serialisation).
If I want to create a derived BaseObject class with specific settings then I can use a method with a generic type constraint.
public void CreateBaseObjectInstance<T>(BaseObjectSettings baseObjectSettings) where T : BaseObject
{
var instance = pool.GetInstance<T>();
instance.Settings = baseObjectSettings;
scene.Add(instance);
}
The problem I am facing is that while I can constrain the generic type to BaseClass I can't constrain the BaseClassSettings to the relevant derived BaseClass. This means that I can do things like
CreateBaseObjectInstance<Banana>(new AppleSettings());
which seems a bit terrible.
What are my options given that I am currently constrained to both creating and initialising the object in the same method before adding it to the scene?
One way is to have all your settings classes inherit from a generic base class. The generic base class could then inherit from BaseObjectSettings
. The generic type parameter indicates what kind of object this settings class is for.
For example, for your AppleSettings
,
class AppleSettings: ObjectSettings<Apple> {
...
}
abstract class ObjectSettings<T>: BaseObjectSettings where T: BaseObject {}
Now, you can change CreateBaseObjectInstance
to accept an instance of ObjectSettings<T>
instead:
public void CreateBaseObjectInstance<T>(ObjectSettings<T> objectSettings) where T : BaseObject
{
var instance = pool.GetInstance<T>();
instance.Settings = objectSettings;
scene.Add(instance);
}
If you pass Banana
as T
, it would expect ObjectSettings<Banana>
, preventing you from giving it AppleSettings
, which is ObjectSettings<Apple>
.
I don't really understand the logic here as things are missing, but from the code provided you can probably write:
public void CreateBaseObjectInstance<TBase, TSettings>(TSettings baseObjectSettings)
where TBase : BaseObject
where TSettings : BaseObjectSettings
Used like that:
CreateBaseObjectInstance<Banana, AppleSettings>(new AppleSettings());
Can be improved to:
public void CreateBaseObjectInstance<TBase, TSettings>(TSettings baseObjectSettings)
where TBase : BaseObject
where TSettings : BaseObjectSettings, new()
{
if ( baseObjectSettings == null ) baseObjectSettings = new TSettings();
...
}
CreateBaseObjectInstance<Banana, AppleSettings>();
But if there is a strong coupling between entity and settings, you should redesign to define dependency with an association using a thing that can also be similar to @Sweeper's and @Moho's answers:
Association, Composition and Aggregation in C#
You need to create a generic interface or base class that where you define the settings type:
public class BaseObject<TSettings>
{
public TSettings Settings { get; set; }
}
Then your method will require two generic arguments - one for the actual object to create TObject
and one for method's argument for the settings TSettings
. You then constrain TObject
to an implementation of the implemented interface or base class/derivation thereof, using generic argument TSettings
as the constraint's type's generic argument
public void CreateBaseObjectInstance<TObject, TSettings>(
TSettings settings
)
where TObject : BaseObject<TSettings>
{
...
}
Example (using above BaseObject
implementation):
public class MyObjectSettings
{
...
}
public class MyObject : BaseObject<MyObjectSettigns>
{
}
Method call:
var settings = new MyObjectSettings(){ ... };
CreateBaseObjectInstance<MyObject>( settings ); // second generic argument should be inferred
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.