Hey,

I am developing a game in C#. I have some question marks in my mind about properties.

-Should I return reference in a get, or should I clone the reference and return a clone?

If I return a reference then in another part of the program, it will be possible to get that reference from get, copy it to another object and modify it, it is bad isn't it?

If I return a clone, then I need to use the private field itself in the class implementing the property, it is bad too isn't it?

What are the best practices about using properties in C#?

What are the best practices about using properties in C#?

Best practice is really no different from parameters and return values from functions. If you can get away with a reference, do so. It's generally more efficient for both space and execution time. Not to mention that it's easier to reason about a single object's lifetime than multiple copies of the object.

Best practice is really no different from parameters and return values from functions. If you can get away with a reference, do so. It's generally more efficient for both space and execution time. Not to mention that it's easier to reason about a single object's lifetime than multiple copies of the object.

Hi Narue, nice new avatar.

Can you please give some examples?

Examples of how do you handle returning references by properties?

Do you just return the reference or return the clone?

If you return the clone, how do you handle assignments to the reference while implementing the class methods without loosing implemented set/get logic in a property?

If you return the reference, how do you make sure that reference will not be modified by external calls?

class Car
    {
        private Engine _engine;

        public Engine Engine
        {
            get { return _engine.Clone(); }
            set
            {
                if(value.HP > 200)
                {
                    throw new Exception("Too much power for the current car model!");
                }

                _engine = value.Clone();
            }
        }

        public Car()
        {
            // Use property to ensure property logic runs
            Engine = new Engine(400); // Edit: OK, set to the clone of the value

            // Use reference but loose the property logic, loose events in the property too
            _engine = new Engine(400); // This one bypasses the 200 HP limit in the property logic
        }
    }

Edited 5 Years Ago by Tellalca: n/a

OK, I think I got it.

When setting, I should set to the clone of the value so that any modify to the value will not affect our reference later.

When getting, I should simply return the clone if it is a reference type.

Examples of how do you handle returning references by properties?

Do you just return the reference or return the clone?

There's no cloning going on:

class Car {
    private Engine _engine;
    public Engine Engine {
        get { return _engine; }
        set {
            if (value.HP > 200)
                throw new ArgumentException("Horsepower too high for car model");

            _engine = value;
        }
    }

    public Car() {
        Engine = new Engine(400);
    }
}

If you're worried about aliases then you can clone on the set of your property:

set {
    // ...
    _engine = value.Clone();
}

But I'd ask for a use case that actually fails due to aliasing, otherwise you're making an unnecessary clone.

The horsepower check is a little odd as well. That doesn't seem like the place it should be to me. The restriction for placing an engine in a car really has nothing to do with horsepower. In fact, unless you're supporting some sort of feature for non-stock engine swaps, it would be best to base the engine on the model and not expose a public set at all:

abstract class Car {
    public Engine Engine { get; protected set; }
}

class SomeSpecificModel: Car {
    public SomeSpecificModel() {
        Engine = new Engine(400);
    }
}

Now the horsepower is a non-issue because it's assumed to be stock, and you can use an auto-property.

This question has already been answered. Start a new discussion instead.