Fields vs Properties
As discussed in the comments above, there's a problem with IsVisible
:
private bool isVisible;
public bool IsVisible { get; set; }
When this code compiles, you'll basically get something like this "under the hood":
private bool isVisible;
private bool IsVisible;
public bool get_IsVisible() { return this.IsVisible; }
public void set_IsVisible(bool value) { this.IsVisible = value; }
BUG!
You're using isVisible
all over your code, but the setter for IsVisible
, set_IsVisible
, is never called. Hence your clients will not see the right value... literally: the public getter will always return default(bool)
... false
!
You really have two options.
Either you expose data, or you encapsulate data.
Think of what a class really is: it's a definition for a type. A type can be a class
, but in C# you can also have an enum
, a struct
, an interface
... types can also be abstract (like an interface
, or an abstract class
).
When you instantiate a class, you create an object of the type defined by the class. An object has an interface (do not confuse with interface
) that exposes everything that's publicly available. The client code doesn't "see" anything that's private
or protected
(or internal
if the client code is in another assembly). And that's exactly where encapsulation is: it's hidden, encapsulated inside the inner workings, the implementation details of the type - the interface doesn't expose it because client code does not need to know what the implementation details are.
Fields are implementation details. They don't need to be exposed, and doing so breaks encapsulation.
Option One
You could make IsVisible
an auto-property:
public bool IsVisible { get; set; }
Or, for a get-only auto-property:
public bool IsVisible { get; private set; }
Remember that under the hood, there is a private field for that auto-property (see "When this code compiles..." above).
Option Two
You could make IsVisible
a property that uses a _isVisible
private backing field:
private bool _isVisible;
public bool IsVisible
{
get { return _isVisible; }
set { _isVisible = value; }
}
The get-only version simply omits the setter.
You'll notice I'm using a naming convention that makes it a no-brainer to tell a field (_isVisible
) from a parameter (value
- implicit parameter in a property setter).
If you don't like having an underscore prefix on your private fields (it really comes down to personal preference.. or to the naming conventions your team is using), you could alternatively do it like this:
private bool isVisible;
public bool IsVisible
{
get { return this.isVisible; }
set { this.isVisible = value; }
}
The this
qualifier isn't really needed (it's actually redundant in this case), but then if you had a method like this:
private void DoSomething(bool isVisible)
{
// "isVisible" in this scope refers to the parameter.
// use "this.isVisible" to refer to the private field.
}
And this is why I prefer the underscore prefix.
Bottom line: Properties win.
Some useful references:
We exclude constant and static read-only fields from this strict restriction, because such fields, almost by definition, are never required to change.
- X DO NOT provide instance fields that are public or protected. You should provide properties for accessing fields instead of making them public or protected.
- √ DO use constant fields for constants that will never change. The compiler burns the values of const fields directly into calling code. Therefore, const values can
never be changed without the risk of breaking compatibility.
- √ DO use public static readonly fields for predefined object instances. If there are predefined instances of the type, declare them as public read-only static fields of the type itself.
- X DO NOT assign instances of mutable types to readonly fields.
Note that in oop, static, predefined instance is generally just bad wording for don't do that!!
Also while you certainly don't want a mutable readonly struc, but readonly
in front of a reference type only means that the reference cannot be reassigned. These are guidelines after all ;)
- √ DO create get-only properties if the caller should not be able to change the value of the property. Keep in mind that if the type of the property is a mutable reference type, the property value can be changed even if the property is get-only.
- X DO NOT provide set-only properties or properties with the setter having broader accessibility than the getter. For example, do not use properties with a public setter and a protected getter. If the property getter cannot be provided, implement the functionality as a method instead. Consider starting the method name with Set and follow with what you would have named the property. For example, AppDomain has a method called SetCachePath instead of having a set-only property called CachePath.
- √ DO provide sensible default values for all properties, ensuring that the defaults do not result in a security hole or terribly inefficient code.
- √ DO allow properties to be set in any order even if this results in a temporary invalid state of the object. It is common for two or more properties to be interrelated to a point where some values of one property might be invalid given the values of other properties on the same object. In such cases, exceptions resulting from the invalid state should be postponed until the interrelated properties are actually used together by the object.
- √ DO preserve the previous value if a property setter throws an exception.
- X AVOID throwing exceptions from property getters.
Abstraction
If I look at the interface of an Asteroid
, I see these members:
Asteroid(Texture2D newTexture, Vector2 newPosition);
Rectangle BoundingBox { get; }
Vector2 Position { get; }
bool IsVisible { get; set; }
void LoadContent(ContentManager content);
void Draw(SpriteBatch spriteBatch);
void Update(GameTime gameTime);
I would think pretty much everything that's drawable in your game has a very similar interface, if not an identical one.
If you defined an abstraction for the methods this interface exposes...
public interface IDrawableContent
{
void LoadContent(ContentManager Content);
void Draw(SpriteBatch spriteBatch);
void Update(GameTime gameTime);
}
Then you could have every drawable game component implement that interface, like this:
public class Asteroid : IDrawableContent
And since your GameScreen
(I'm making this up) also has these methods with the same signature, why not do this as well:
public class GameScreen : IDrawableContent
Your AsteroidZapperGame
class (or whatever it's called) also has similar methods (defined by the XNA Game
class), but it's pretty much your top-level object, so you don't need it to implement the interface.
What gives?
The GameScreen
class might roughly look like this (over-simplified):
public class GameScreen : IDrawableContent
{
// _items is readonly.
// its reference may only be assigned in a constructor.
// items may still be added or removed from the list any time.
private readonly IList<IDrawableContent> _items;
public GameScreen(IList<IDrawableContent> items)
{
_items = items;
}
public void LoadContent(ContentManager content)
{
foreach (var item in _items)
{
item.LoadContent(content);
}
}
public void Draw(SpriteBatch spriteBatch)
{
foreach (var item in _items)
{
item.Draw(spriteBatch);
}
}
public void Update(GameTime gameTime)
{
foreach (var item in _items)
{
item.Update(gameTime);
}
}
}
This class has no clue that you're making it draw asteroids. In fact, it could just as well be drawing bubbles in a soda can, or a bunch of zombies hunting the player down. That's what abstractions do: they abstract away the implementation details, and that makes code easier to read, extend, and maintain.
if (isVisible)
? \$\endgroup\$IsVisible
) { asteroidList.RemoveAt(i); i--; } } The property gets used here, I believe? (Sorry, getting a bit confused. isVisible is the FIELD, and IsVisible is the PROPERY, am I right?) \$\endgroup\$