OK, I know why we don't use constructors on monobehaviors in Unity. For nearly all of the use cases, Start and Awake fit perfectly. Usually.
However, there's a great C# feature that only can be used with constructors — readonly fields. In my particular situation, I work on a project with a lot of developers and write an abstract MonoBehavior that will be subclassed and rewritten a lot of times by a lot of different people. And I want a field to act like constant throughout object's lifetime (or it WILL introduce strange, hard-detectable bugs) but with different values in different subclasses — in other words, a classic use-case for a readonly field. (I don't want to use properties because they have no language-enforce obligation of staying the same.)
So — can I safely use MonoBehavior's constructors? Won't some strange dragon come out of the lair somewhere down the road? What should I know if I choose to use them?
I think the main reasons Unity wants you to stay away from using the constructor is that the constructor isn't called on the main thread, and the constructor is called before serialized data is restored to the object.
So if the readonly fields you're setting in the constructor depend on data from serialized fields, then they won't work right. And if they don't then you can just assign them at initialization.
You could also use a container object to keep your readonly values, but there's nothing stopping someone else from re-assigning that container later.
using UnityEngine;
using System.Collections;
public class ReadOnlyTest : MonoBehaviour {
public string part1 = "alpha"; // change these values in the editor and
public string part2 = "beta"; // see the output of the readonly variable "combined"
public readonly string combined;
// just assign to readonly vars.
public readonly string guid = System.Guid.NewGuid().ToString();
public readonly float readOnlyFloat = 2.0f;
public class ReadOnlyContainer {
public readonly int readOnlyInt;
public readonly float readOnlyFloat;
public readonly string readOnlyString;
public ReadOnlyContainer(int _int, float _flt, string _str) {
readOnlyInt = _int;
readOnlyFloat = _flt;
readOnlyString = _str;
}
public override string ToString() {
return string.Format("int:{0} float:{1} string:{2}", readOnlyInt, readOnlyFloat, readOnlyString);
}
}
public ReadOnlyTest() {
combined = part1 + part2;
}
public ReadOnlyContainer container;
void Awake() {
if (container == null) {
container = new ReadOnlyContainer(Random.Range(-100,100), Time.realtimeSinceStartup, System.Guid.NewGuid().ToString());
}
}
void Start () {
Debug.Log(container.ToString());
Debug.Log("combine1: " + combined);
Debug.Log("guid: " + guid);
}
}
Many unity classes are created by reflection, and there's no way for unity to non-default constructors properly; hence the limitation.
#Calvin's answer points out one very good option: create classes that are not derived from MonoBehaviour; these can have constructors like any other C#. You can put those classes into fields in MonoBehaviours as long as your code can tolerate missing instances. If you use the typical quasi-singleton pattern from #Calvin's answer you'll always get an instance when you need one, and you can push the 'give me an instance the first time' logic into a method that can be overridden in derived classes to customize behavior.
If you want constant-like behavior, with the option of different values in derived classes it may be easier to define a method rather than a field. The method is effectively read-only, and it has more predictable mutations as per #Jerdak's answer.
If you must have constructors, the last option is to use the monobehavior as a minimal placeholder and write all of the interesting stuff in a class of your own, then delegate all of the work in the Monobehavior to your class.
using UnityEngine;
using System.Collections;
public class OuterPlaceholder: MonoBehaviour {
public InnerBehavior _Inner;
public void Awake() {
if (_Inner == null) {
_Inner= new InnerBehavior(4);
}
}
public void Update()
{
_Inner.DoUpdate(this);
}
}
public class InnerBehavior
{
public readonly int UpConstant;
public InnerBehavior (int up)
{
UpConstant = up;
}
public void DoUpdate(MonoBehaviour owner)
{
owner.transform.Translate(Vector3.up * UpConstant * Time.deltaTime);
}
}
This option may work best if you are sure you're going to get a lot of complex inheritance as the project evolves.
Finally: It's perfectly OK to name the field _ReadOnlyField or _DoNotWrite or whatever to tell users not to muck with it. All Python programmers live with the possibility of somebody doing far worse things and it seems to work out fine most of the time :)
From the script refs:
If you attempt to define a constructor for a script component, it will
interfere with the normal operation of Unity and can cause major
problems with the project.
MonoBehaviours are constructed many times during serialization, something Unity does quite frequently in the editor and I suspect there is a lot more going on the hood to hook the C layer to C#. Ultimately the behavior is undefined so it's best not to try.
Regarding "but with different values in different subclasses", from MSDN:
assignments to the fields introduced by the declaration [readonly] can only occur as part of the declaration or in a constructor in the same class.
So no modification in derived classes.
Related
I've a simple code base with few 'weapon' concrete classes which implements different contracts in order to be used by its clients.
My contracts:
public interface IWeaponPrimaryAttack
{
void DoAttack();
}
public interface IWeaponSecondaryAttack
{
void DoSecondaryAttack();
}
public interface IReloadable
{
void Reload();
}
Concrete implementation or the actual weapons:
public class Katana : IWeaponPrimaryAttack, IWeaponSecondaryAttack
{
public void DoAttack(){Console.WriteLine ("Swing");}
public void DoSecondaryAttack() {Console.WriteLine ("Stab");}
}
public class ShotGun : IWeaponPrimaryAttack, IReloadable
{
public void DoAttack(){Console.WriteLine ("Swing");}
public void Reload() {//reload it}
}
Clients that uses these concrete classes:
public class PrimaryAttack
{
private IWeaponPrimaryAttack _attack;
public PrimaryAttack(IWeaponPrimaryAttack attack)
{
_attack = attack;
}
public void DoAttack()
{
_attack.DoAttack();
}
}
public class SecondaryAttack
{
private IWeaponSecondaryAttack _attack;
public SecondaryAttack(IWeaponSecondaryAttack attack)
{
_attack = attack;
}
public void DoSecondaryAttack()
{
_attack.DoSecondaryAttack();
}
}
public class WeaponReload
{
private IReloadable _reloader;
public WeaponReload(IReloadable reloader)
{
_reloader = reloader;
}
public void Reload()
{
_reloader.Reload();
}
}
New of course the instantiation of concrete class only be known when the user selects one among many weapons(one among ShotGun, Katana, etc).
Let say the use has selected ShotGun as the weapon, based on the selection it might go like this:
IWeaponPrimaryAttack weapon = new ShotGun(); // get it from a factory
PrimaryAttack primaryAttack = new PrimaryAttack(weapon);
primaryAttack.DoAttack();
Now for the WeaponReload have to do a typecast here in order to use it.
WeaponReload reloader = new WeaponReload ((IReloadable)weapon);
reloader.Reload();
I have questions around it,
Should I really have to end up typecasting eventually?
Or there is a better way to handle this object creation part.
Or there is entirely a better design that I can come up with which
does not necessarily ends up in casting.
Or casting it like this is totally fine.
Not so sure why you need all these extra delegating wrappers? Anyhow, there's a few things at play here.
Maximizing composition
You've used a concrete type per weapon type here, but you could also put more emphasis on composition and have a single all-encompassing Weapon class that delegates all it's inner workings to strategies.
e.g.
Rather than Weapon shotgun = new Shotgun(); you could have Weapon shotgun = Weapons.shotgun() where the factory method may look like:
return new Weapon.Builder()
.withPrimaryAttack(...)
.withoutSecondaryAttack()
.withSlowReload().build();
Maximizing composition makes the design very flexible and could allow you to introduce new weapon types dynamically if needed or even change certain aspects of a weapon at runtime (e.g. shotgun now fires knifes b/c of a picked-up powerup).
Following the ISP
In the composition-based approach described above, you may notice that the Weapon's interface will become bloated with all sort of things weapons can do. Clients depending on the Weapon class will indirectly depend on all the various implicit interface methods they may never call.
In order to reduce clients coupling you could very well make sure that Weapon features are segregated into many interfaces such as IReloadable, etc. The Weapon class would implement them all, but client code interested in only a subset of weapon features could still depend on these interfaces rather than Weapon.
e.g.
reload(weapon);
void reload(IReloadable reloadable) {
if (stamina < ...) throw ...;
reloadable.reload();
}
ISP & feature-detection
Considering your original design, I don't think there's anything fundamentally wrong with using instanceof as a feature detection mechanism.
Using instanceof to match concrete types is certainly wrong, but matching interfaces is most likely fine.
weapon instanceof Shotgun //bad
weapon instanceof IReloadable //ok
Note that you should always check with instanceof before casting. Also note that you need to think of an approach to make weapon implementers know the set of potential weapon-feature interfaces they could implement.
I am coding an application that I thought would be a good chance to use a base class. I have Player class which holds an instance for each player on my game, I also have a PlayerManager class that has a dictionary of all the connected players, although I'll leave the PlayerManager class out of this question as this is just about the Player and PlayerData class.
So, I thought instead of having something like this, please note before checking this code snippet that I have removed a lot of the code and just shown a minimal example.
class Player
{
public PlayerData;
}
class PlayerData
{
public string Username;
public string Motto;
public string NickName;
}
class SomeOtherClass
{
public void Test()
{
var player = GetPlayer();
Console.WriteLine("Hello, I am " + player.PlayerData.Username);
}
}
I thought why have a method when I can have a base class? So I thought great, lets use a base class, this is what I ended up with.
internal class Player : PlayerData, IDisposable
{
private readonly Socket _socket;
private bool _disposeCalled;
private bool _receivingData;
private bool _hasAuthenticated;
public Player(Socket socket)
{
_socket = socket;
}
public void OnAuthenticated(MySqlDataReader reader)
{
if (_hasAuthenticated)
{
return;
}
_hasAuthenticated = true;
AssignData(reader);
}
public void Dispose()
{
if (_disposeCalled)
{
return;
}
_disposeCalled = true;
if (_receivingData)
{
_receivingData = false;
try
{
if (_socket != null && _socket.Connected)
{
_socket.Shutdown(SocketShutdown.Both);
_socket.Close();
}
}
catch
{
// ignored
}
_socket?.Dispose();
}
if (_hasAuthenticated)
{
SaveData();
}
}
}
internal class PlayerData
{
public int Id;
public string Username;
public void AssignData(MySqlDataReader reader)
{
while (reader.Read())
{
Id = reader.GetInt32("id");
Username = reader.GetString("username");
}
}
public void SaveData()
{
using (var dbConnection = Program.Server.Database.Connection)
{
dbConnection.SetQuery("UPDATE `users` SET `username` = #username WHERE `id` = #id");
dbConnection.AppendParameter("id", Id);
dbConnection.AppendParameter("username", Username);
dbConnection.ExecuteNonQuery();
}
}
}
You'll probably see the base class has a constructor, that's because I was going to just pass the PlayerData's data with the Player's constructor, but I wont actually get the data untill the Player's class has been fully initialized, I don't know when that will be as its done via socket packets, I just assign the data when I notice its been authenticated.
The point of my question is, should I use a base class like this, or should I not use a base class due to the fact I'm not initializing the data via the constructor, or is it okay to assign it via another method later on? Do I really need a base class, am I not following the right official rules for what a base class is and used for? Basically I just want to know, with this call stack should I be using a base class or method? I'm unsure on the rules.
So, the rules are not rules so much as guidelines (that not everyone really agrees on).
THAT SAID, I don't really see any benefit of lumping these classes together, although that could be because of so much of the code being removed.
In general, a good rule of thumb is not to use inheritance unless you have a good reason--a significant amount of code reuse that couldn't be achieved through composition, for example. In most cases, your code will be easier to maintain if you design with an eye for reducing dependencies (coupling), and the dependency between a subclass and its superclass is very strong. This means keeping things separate.
One technique you could do to simplify calls to player data is to "promote the interface"--basically, add the methods/properties you want as a sort of facade on the Player class, and have that relay the code to its PlayerData object. This has a few benefits:
1. It hides dependencies on PlayerData, which means you are free to change implementation to consolidate or use a different type (for example, if you just wanted to put those values in a data structure in the Player class)
2. It allows you to handle the case where PlayerData is being requested, but hasn't been initialized yet. For example, you could return default values or throw a custom exception.
3. Player and PlayerData are free to vary independently. So, if you run across a valid reason to subclass one or both of them, you won't be constrained.
In summary, it doesn't look like you really gain much from using inheritance in this way, but it would cut off design choices down the road. Also, anytime you are using inheritance to describe a relationship that is not an "IS A" relationship (PlayerData Is A Player? nope)--that smells fishy.
Again, guidelines. Bottom line is you want to design a system that you want to maintain, and design decisions come with trade-offs (often between simplicity and flexibility). So, if you decide there is a good reason to keep this as a subclass, just document it and don't worry about the OO Police coming after you for breaking the rules ;)
Here is the conundrum. I have a specific set of state variables that are used in almost every supporting object I have, and I want those variables to be able to be read by any object that needs to read them, but I want to protect them so that only 1 object has the ability to set them.
For example, lets say I am making a poker game. Variables like:
- Minimum Ante
- Maximum Bet
- Maximum Number of Players
- Current GameState (Placing Bets, Shuffling, Dealing, Paying, etc.)
Personally, I prefer small compact component classes, so lets say I have the majority of the poker game logic in 1 controller class, but i have 50 supporting objects that handle everything that isn't the poker game logic itself, such as a PlayerInterface, a graphics controller, 'The Deck' to handle shuffle and deal logic, etc. Alot of my smaller support classes need to see what the minimum ante is, and the current method I am using is for the controller class to pass these variables into the supporting classes as parameters.
The obvious downside to this is I have 50 supporting objects all holding on to their own local variables for minimum ante to hold the same information that I am passing to them from the controller. Wasted parameters, memory, and opens a ton of risk if any of those variables ever get out of sync.
So, how to I make these variables global so everyone can access and read them? The knee jerk reactionary answer is some public static variables, however this presents the problem that anyone could also write to them. Not only do I not want my supporting objects having the power to change the minimum ante without the controller's knowledge, but I also don't want the client shell that holds the poker game to be able to change them without first going through the proper checks contained in the controller.
So what do I do? Someone once mentioned to me the idea of a Singleton, but after plenty of research, most of it a few years old or more, I found about a 50/50 split in the community who say Singletons are a good idea vs those who think they aren't.
If not singletons or statics, then what? I am open to any ideas to research and try out.
Remember, I want any object, anytime, anywhere to be able to GET the data it needs, but only a very specific object to have the ability to SET the data, should it need to change, so that it can filter through the proper checks. By proper checks, I mean for example in the poker game, if a player has the ability to change the Minimum Bet on the table, he should only be able to do so between hands, or before a tournament begins. I don't want him messing with these things during play.
Thanks in advance for any input.
You could use interfaces approach here.
Declare two interfaces as
public interface IReadOnlyAccess
{
int Property{get;}
}
public interface IFullAccess
{
int Property{get;set;}
}
Then your class would implement both interfaces like
public interface MyClass: IReadOnlyAccess, IFullAccess
{
public int Property{get;set;}
}
Then wherever you need full access you get it via IFullAccess, if otherwise - via IReadOnlyAccess.
Make an inner class, it will have access to the main classes private vars:
public class OuterClass
{
public string StringProperty { get; private set; }
public InnerClass CreateInnerClass()
{
InnerClass ic = new InnerClass(this);
return ic;
}
public class InnerClass
{
private OuterClass _outer;
public InnerClass(OuterClass oc)
{
_outer = oc;
}
public string Prop
{
get
{
return _outer.StringProperty ;
}
set
{
_outer.StringProperty = value;
}
}
}
}
So create the main class that most people have readonly access:
var oc = new OuterClass();
oc.StringProperty = "123"; <-- not allowed, is `readonly`
To write to properties, create inner class instance:
var oc = new OuterClass();
var ic = oc.CreateInnerClass();
ic.StringProperty = "123";
Seems like the cleanest, easiest solution is to have everything done in your controller class.
Let's say something like this:
AS3:
//adding the final keyword, locks this class so others can't extent/inherit from it
public final class MyController {
//create a privately scoped var (it can only be accessed in this class)
private var minBet:Number = 0;
//create a public getter that can be read by any class/object
public function get minimumBet():Number {
return minBet;
}
private function set minimumBet(value:Number):void {
//do you checks etc
minBet = value;
}
}
C#
//sealed in C# is the same as final in AS3
public sealed class MyController
{
private float minBet = 0;
public float minimumBet
{
get { return minBet; }
}
}
instanceOfMyController.minBet //will throw an error
instanceOfMyController.minimumBet = 10; //will throw an error
instanceOfMyController.minimumBet //will supply the value of the minBet var
If you're doing a lot cross-language code, consider checking out something like Haxe which can compile out to AS3 or C# with the same code.
I'm making a map loading system that uses chunks so that the entire map data doesn't have to be loaded at once.
I have a "World" class, and within that class I'm creating an instance of a class called "ChunkManager".
I'm unsure if creating an instance inside another class is a good idea/considered a "normal" thing to do etc. I've not been able to find anything about this while searching the internet.
So my question is: Should I be creating an instance of a class within a class in the way I have, or will there be problems with doing it this way?
Here is my code, if it's relevant:
class World
{
public string WorldName { get; set; }
ChunkManager chunkManager = new ChunkManager();
public World(string worldName)
{
WorldName = worldName;
}
public void AddChunk(int X, int Y)
{
//Plus other validation code here that I didn't paste
chunkManager.AddChunk(X, Y);
}
}
And ChunkManager:
class ChunkManager
{
public int TotalGeneratedChunks { get; private set; }
private List<Chunk> ChunkList = new List<Chunk>();
public bool CheckIDExists(int IDToCheck)
{
foreach (Chunk i in ChunkList)
{
if (i.UniqueID == IDToCheck)
{
return true;
}
}
return false;
}
public void AddChunk(int X, int Y)
{
ChunkList.Add(new Chunk(TotalGeneratedChunks++, X, Y));
}
}
Your code is fine BUT if either class grows to be more complex and you want to be able to test them independently you should instead define an interface IChunkmanager and inject an instance of ChunkManager into World:
class World
{
public string WorldName { get; set; }
private readonly IChunkManager chunkManager;
public World(string worldName, IChunkManager chunkmanager)
{
this.chunkManager = chunkManager;
...
With this approach you can use a mocking framework to inject a mock IChunkManager and can test the World class independently.
In general classes should be loosely coupled. As soon as you new-up an instance of another class within a class you have tightly-bound them in a way that makes it hard to test them independently (or to reuse them in different situations).
It's perfectly fine to create an instance of a class inside another. chunkManager is what is known as a field and the syntax for initializing it inline along with its declaration is called an initializer. You can find more information on initializers and how they are different from initializing via the constructor in this blog series by Eric Lippert
Part 1
Part 2
It might some times be a better idea to initialize fields via the constructor though as this lets you use dependency injection (parameter injection to be precise) which can greatly improve the testability and modularity of your code. If you're interested in learning more about dependency injection I suggest purchasing and reading this book.
Standard practice is to set values inside the constructor because it allows for dependency injection and makes modifying the constructor to use an argument trivially easy.
If you are going to create a lot of World, i suggest creating an Abstract base that implements the ChunckManager.
That way you can leverage the use of base class, promote code reuse. You can also make your ChunkManager singleton since it only needs to be used by the base, and then use a method to actually instantiate the ChunkManager if you need specific properties from maps.
Use DI to pass the prop from child to base to instantiation of the ChunkManager
yes you can use one class type in another class its like one of filed on this class like when you use string a=new string() you use an object of class string its normal code
I am using a list for particles.
List<Particle> particles;
Normally i place this list in my Simulation class. Which calculates position, velocity and other properties of particles.
A few other classes need this particle data for output and post processing.
is it OK to create a static class,
static class Particles
{
static List<Particles> plist;
}
to access particle data from other classes?
I would recommend staying away from static classes/methods whenever possible. They tend to lead to high coupling of code. Although there are some cases where it's far faster to use them (hopefully sparingly).
I'm not quite sure what you are going for from your question, but I would at least recommend changing the static class to expose a property instead of a field.
public static class Particles
{
public static List<Particles> PList { get; set; }
}
or
public static class Particles
{
private static List<Particles> _plist;
public static List<Particles> PList
{
get { return _plist; }
set { _plist = value; }
}
}
This way you encapsulate the list a little more. For example, you can check for null values during the getter or setter.
You have at least two options here:
Create an IList<Particles> property in each class that operates on particles.
In each class that operates on particles, create a private IList<Particles> field and a constructor that takes such a list as a parameter.
Either of these options will preserve encapsulation of the list.