1

I'm making a game which involves placing objects in a room. The room stores a list of objects that can be placed in it, e.g.

List<RoomObject> possibleObjects = new List<RoomObject>(){ new Bed(), new Table() };

These objects are then each sent to buttons which allow the user to click the button, entering a placement phase for the chosen object, where the user then clicks in the room, and the object is placed.

e.g.

public Room currentRoom;
public RoomObject currentObject;
//...
public void onClick()
{
    if (CanPlace) currentRoom.Add(currentObject);
}

My problem is, if the user wants to place more than one of the same object, the current way it's set up will mean the exact same object will be added to the room, and if that object is later edited in some way (e.g. Bed.occupied = true), it will affect all of the objects of that type in the room.

Is there a way to duplicate an object (to get a separate reference) without me having to use reflection (which I'm not very familiar with, and feel is unsafe code).

I assume the reflection way would be passing around a Type and then having to call constructors using Type.GetConstructor, but I'd rather not do this if possible. If reflection is the only way, could someone provide example code for how to do it?

EDIT - perhaps I need to specify that my variable currentObject will not hold a variable of Type RoomObject, but a subclass such as Bed. (Bed inherits from RoomObject).

Haighstrom
  • 577
  • 5
  • 16

4 Answers4

4

You should define a copy constructor for your object. This will allow you to instantiate a class based on values from another instance of that class. Here is a tutorial:

http://msdn.microsoft.com/en-us/library/ms173116(v=vs.80).aspx

public class RoomObject
{
    public RoomObject(RoomObject roomObject)
    {
    //Copy room object properties
    }
}

public class Bed : RoomObject
{
    public Bed(Bed bed) : base(bed)
    {
    //Copy Bed properties
    }
}

Usage

Bed bedOne = new Bed();  

Bed bedTwo = new Bed(bedOne);  //Create a bed using Bed copy constructor

RoomObject roomObject = new RoomObject(bedOne)  //Creates a room object using RoomObject copy constructor

Further Edit

public abstract class RoomObject<T> where T : new()
{
    protected T CreateRoomObjectCopy(T roomObject)
    {
        T concreteType = new T();
        //Copy Room object properties
        return concreteType;
    }

    public abstract T Copy(T roomObject);
}

public class Bed : RoomObject<Bed>
{
    public override Bed Copy(Bed roomObject)
    {
        Bed newBed = CreateRoomObjectCopy(roomObject);
        //Copy bed properties
        return newBed;
    }
}
Justin Harvey
  • 14,446
  • 2
  • 27
  • 30
  • This looks useful, but all my objects inherit from RoomObject. If I'm currently placing a Bed (which has additional properties to RoomObject), how can I reference Bed's own constructor? I have a reference to the specific instance of my bed, but it's held in a variable of type RoomObject. I can't do new RoomObject(currentObject), because currentObject will be a child class? – Haighstrom Dec 12 '12 at 14:07
  • Each class can define its own copy constructor. It can call the base constructor for the common class data, then copy the extended fields. See my example above. – Justin Harvey Dec 12 '12 at 14:09
  • @Haighstrom you could also make an `abstract` `Copy` method which means that `Bed` will have to implement it. Then when you have a `Bed` and execute the method via the interface it will execute the right method. – Mike Perrenoud Dec 12 '12 at 14:11
  • @JustinHarvey So how would I call the Bed's (or other RoomObject subclass') constructor? If I just call new RoomObject(currentObject), where currentObject is of type Bed, will that instantiate a Bed, rather than a RoomObject, using your code above? – Haighstrom Dec 12 '12 at 14:16
  • @Haighstrom, see my edits above for usage. A base class constructor can only instantiate an object of its own type. – Justin Harvey Dec 12 '12 at 14:30
  • This isn't going to work then. My Button class gets a reference to an instance of Bed or Table (both inheriting from RoomObject). When the user clicks the Button, the currentObject is passed to that RoomObject (so currentObject is either bedOne or tableOne). When the user clicks, I add bedOne or tableOne to the Room. After that I need bedTwo (if before we had bedOne) and tableTwo (if before we had tableTwo). Instead, should I just pass through the Type (either typeof(Bed) or typeof(Table), and when it gets to the point of creation do Room.Add(Activator.CreateInstance(currentObjectType)); ? – Haighstrom Dec 12 '12 at 14:38
  • @Haighstrom, you could avoid reflection by having a copy method that detects the type by casting and then uses the copy constructor of the appropriate type. – Justin Harvey Dec 12 '12 at 14:54
  • but what would I write after the new keyword to call the constructor? i don't really want a huge if loop of if(object is Bed) return new Bed() etc. i don't see how i call the constructor of an unknown Class (which all I know is that it inherits from RoomObject) without reflection. – Haighstrom Dec 12 '12 at 15:00
  • You could do it using generics with a copy method. – Justin Harvey Dec 12 '12 at 15:06
2

Either use a Copy Constructor or with reflection.

With reflection it's not as complicated as you imagine, it's a matter of using the Activator class along with the Type and you can obtain an instance of that Type.

dutzu
  • 3,883
  • 13
  • 19
  • I think I need to use reflection using Activator.CreateInstance(currentObjectType). My question doesn't fully explain the structure of my code - i never instantiate RoomObject - only Bed or Table which inherit from RoomObject, so I can't copy a Bed as I don't know which type of RoomObject it is. – Haighstrom Dec 12 '12 at 14:42
0

There's nothing really unsafe about reflection. It's one of the beauties of managed languages like .NET.

I may be wrong but it sounds like you want to clone an object instance (as opposed to having two references to the same instance).

Take a look at the following links.

Deep cloning objects

How to Clone Objects

Additional:

You could try implementing ICloneable, thus providing a mechanism of your own to clone the object

Exmaple:

public class RoomObject : ICloneable
{
    public object Clone()
    {
        return new RoomObject { X = this.X, Y = this.Y, Z = this.Z };
    }
}


RoomObject ro = new RoomObject();

RoomObject ro2 = (RoomObject)ro.Clone();
Community
  • 1
  • 1
Matthew Layton
  • 39,871
  • 52
  • 185
  • 313
0
class Program
{
    static void Main(string[] args)
    {
        Bed bed = RoomObject.RoomName("Bed");
        Console.WriteLine(bed.name);
       //outline:Bed
        Console.Read();
    }
}
public class RoomObject
{
    public static Bed RoomName(string BedName)
    {
        Bed newBed = new Bed();
        newBed.name = BedName;
        return newBed;
    }
}
public class Bed
{
    public string name { get; set; }
}