[C#] Changing parent variable without constructor

Started by stripe103, August 20, 2012, 02:45:43 pm

Previous topic - Next topic

stripe103

August 20, 2012, 02:45:43 pm Last Edit: August 20, 2012, 02:53:14 pm by stripe103
Okay, so I've been trying this all afternoon, but can't make it work properly.
I'm making a basic kinda of event-system for our Unity3D project, and I'm having trouble.

Basically, I want to have two(for now) strings in every class that derives from the class EventCommand.
Those variables are then going to be read by the Unity editor script by using something like

foreach (EventCommand cmd in eventCommands) {
  if (cmd.CommandName != null) {
    eventBase.tabs[selectedTab].commands.Add(cmd);
  }
}


that will then add the command to a list of commands.

Problem is that I can't get it to read anything more than an empty string, or whatever is set in the EventCommand class.
So I want to be able to change those two variables (or functions, if that's better) into returning custom strings for each class that inherits from it.

I've tried using functions (both normal like the ones below, as well as using virtual or abstract and overriding them)

Code: EventCommand.cs

public class EventCommand {
  // Preview of command configuration
  public string CommandString() {
    return "";
  }

  // Name shown in list of commands
  public string CommandName() {
    return "";
  }
}


Code: EventMessage.cs

public class EventMessage : EventCommand {
  public new string CommandString() {
    return "Show Message: Text here";
  }

  public new string CommandName() {
    return "Show Message";
  }
}


And I've tried using normal variables (as below, as well as using const, basically, I've tried everything I can think of.)

Code: EventCommand.cs

public class EventCommand {
  // Preview of command configuration
  public string CommandString = "";

  // Name shown in list of commands
  public string CommandName = "";
}


Code: EventMessage.cs

public class EventMessage : EventCommand {
  public new string CommandString = "Show Message: Text here";
  public new string CommandName = "Show Message";
}


Am I just stupid, missing something, or is there a better way to do this?
If someone experienced could help me with this, as it's a school project that's pretty important, I'd be very grateful.

ForeverZer0

Make a property and set it as virtual.

public virtual string CommandString {get; set; }


Now derived classes can inherit the property.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

stripe103

August 20, 2012, 04:26:09 pm #2 Last Edit: August 20, 2012, 04:27:41 pm by stripe103
Hmm... simple as that, eh..
I guess I should start using properties more often..
I'll test it out tomorrow.

But why wouldn't it work with the methods that I made? Why didn't the other classes override at all?

ForeverZer0

You have to specify methods that override, otherwise they use the parent class method.

In Parent:
public virtual void DoSomething() {}


In Child:
public override void DoSomething() {}
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

stripe103

August 20, 2012, 04:36:37 pm #4 Last Edit: August 20, 2012, 04:44:36 pm by stripe103
That's what I did though, and then I tried getting it with ParentClass class = new ChildClass(); class.DoSomething();

ForeverZer0

Why would you do this? :
ParentClass class = new ChildClass(); class.DoSomething();


If the class is derived from the parent, and the method is set to "virtual", as long as you don't override the method, it IS calling the parent's method. I don't understand what you are you are trying to do by creating an instance of ParentClass by instantizing and casting a ChildClass. In the example you gave above, "class" is an instance of a ParentClass, not a ChildClass. It is uses and implicit cast, and won't throw an error since the constructor is a derived class.

Think of this example:
using (Stream str = File.OpenRead("somefilename.dat")) { <CODE HERE> }


"File.OpenRead" returns a FileStream object, not a Stream object, but in the example, "str" is an instance of a Stream, not a FileStream. Basically it becomes whatever the declaration is on the left, not the constructor on the right.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

stripe103

August 21, 2012, 01:06:10 am #6 Last Edit: August 21, 2012, 01:16:57 am by stripe103
Reason why I do it is because then I can store any childclasses in the ParentClass variable. Like I do in the game items for example:
Item item = new Apple();
return item.Name;  // Returns 'Apple'
item = new Potion;
return item.Name;  // Returns 'Potion'


This way, it's easier for me to loop through all Item() in for example my inventory and then get the name of each one, even though they are all different subclasses(or whatever it's called) and show on the screen.
Or I can call the Use method of the chosen item.

It probably isn't the best way to do it, even using Interfacea would probably be easier(learned about them only three days ago), but it works, and having only programmed C# in about a year, I'm pretty proud of the result so far. And as I learn more, I will most likely go back and redo things I can do better.

ForeverZer0

Yeah, an Interface would be the way to go with that. That's pretty much what they are used for. Just create an interface, make empty declarations within it, have your classes derive from it, and implement the methods within it. You will then be able to loop through them just as you need.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

stripe103

I think I'll keep the classes until I've learned how to work with interfaces, because I just tried, and it didn't work as easy right now, but I'll keep it in mind later.

Thank you for reminding me of properties though, it worked perfectly.

G_G

August 21, 2012, 09:52:52 am #9 Last Edit: August 21, 2012, 09:53:55 am by gameus
Interfaces are just as easy as making classes.

interface Item
{
   public string Name { get; set; }
   void OnUse();
}

class Apple : Item
{
   public Apple()
   {
       Name = "Apple";
   }

   public void OnUse()
   {
       Console.WriteLine("Apple OnUse");
   }
}

Item apple = new Apple();
Console.WriteLine(apple.Name);
apple.OnUse();

stripe103

Yeh, I guess I'll have to change that later when I have time. It's just that sometimes I want to have a method in the parent class to run after it's override method in the child class have been. Can you do that with interfaces? Just do like

public override void Something() {
  // Do thingiez
  base.Something();
}

ForeverZer0

If the child class derived from the parent. Interfaces do not implement any actual logic, they just declare properties/methods. They are handy because C# does not support multiple-inheritance of classes, but you can inherit from as many interfaces as you like.

They basically just create a common link saying: "this class will contain these properties/methods".
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

stripe103

...sooo, you can't. Then I can't use interfaces all the time, but I will use them most of the times though :)

ForeverZer0

I don't understand what your last post meant. I think you may have misunderstood what I said.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

This is where you use a class or abstract class instead of an interface.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

ForeverZer0

There is no "base" when deriving from an interface. I'm guessing you want the base class to have fuctionality, so that "base.DoSomething()" does something. If that's the case, then an abstract class is not the way to go.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

Blizzard

An abstract class is only used if you have data but still need abstract methods. Obviously this class can have other methods which may or may not be abstract, that's what I was trying to say.
Check out Daygames and our games:

King of Booze 2      King of Booze: Never Ever
Drinking Game for Android      Never have I ever for Android
Drinking Game for iOS      Never have I ever for iOS


Quote from: winkioI do not speak to bricks, either as individuals or in wall form.

Quote from: Barney StinsonWhen I get sad, I stop being sad and be awesome instead. True story.

stripe103

Quote from: ForeverZer0 on August 21, 2012, 12:22:29 pm
I don't understand what your last post meant. I think you may have misunderstood what I said.


This is what I understood:

Can you do that with interfaces? Just do like...
If the child class derived from the parent. (Which I automaticly added ", yeah" after it.)
Interfaces do not implement any actual logic (Meaning you can't do what I asked)

So yeah, one of us misunderstood the other.

stripe103

August 23, 2012, 06:44:42 am #18 Last Edit: August 23, 2012, 06:51:13 am by stripe103
Okay, so I've run into another problem. It turns out that, to be able for Unity to save the values in each scene(which I need),
it is neccessary that it is variables, not properties.
I tried using interfaces, but they can't do variables, and when trying with an abstract class, I don't seem to be able to override
variables, so that doesn't work either.

So, somehow, I need a base class/interface/whatever where I can declare:

public string Name; // Name of the command, this will not change from the value set by each child class.
// Since the Name won't change, I guess it would work with a property that just get's a set string, but it's just so
// you know.

public string CommandString; // Used to get a preview of the command configuration
public Color CommandColor; // The color shown in the editor
public Transform thisTransform; // A reference for the command to be able to get it's own gameObject
public bool IsDone; // If true, goes to the next event command

// Run when scene is started
public void Start();
// Run once every frame, if the command is active.
public void Update();
// Run when needed. Might be multiple times per frame, if the command is active
public void OnGUI();
// Run when editor window is updated
public void DrawEditor();


These will then be needed to be accessed from each child class.

Anyone know a simple solution to this?

PS: Sorry if I'm a bit of a pain, but this is the easiest way for me to learn without needing to take a class in it.

ForeverZer0

Have the get/set og the properties change the values of the fields.
Its against C# convention to have fields accessed directly from outside the class. You should use a property to set them if you need to use them from outside.
I am done scripting for RMXP. I will likely not offer support for even my own scripts anymore, but feel free to ask on the forum, there are plenty of other talented scripters that can help you.

stripe103

August 23, 2012, 10:13:15 am #20 Last Edit: August 23, 2012, 10:27:52 am by stripe103
Yeh, I know you should use properties, but with Unity, public variables is just as easily accessed, so you might as well use them instead, but I'll try.

Edit:
Oh wait... when using System.Activator.CreateInstance, is the constructor triggered? If so then this whole conversation was unnessecary :)

stripe103

August 28, 2012, 07:59:35 am #21 Last Edit: August 28, 2012, 08:02:50 am by stripe103
DOUBLE POSSSSSSSTTTTTTT!!!!

Once again, I need help with the system I'm currently trying to get to work..
For the last problem, I managed to fix it using virtual methods(which I tried before too, but couldn't get to work),
now there is just one thing left to fix.

Because I use child classes for each Event Command, it doesn't load the correct class,
and loads the information into EventCommand instead of EventMessage in this case, so it uses
those methods instead.

I have a simple way of saving the class type ID, that I use for listing all commands. I just need some simple way to use the
methods in the child classes instead of using the EventCommand ones, that doesn't do anything.

I thought of doing something like this
(eventCommands[cmd.classTypeID].GetType())cmd.Update()

or
cmd.Update() as eventCommands[cmd.classTypeID].GetType()

Of course, none of those worked, it was just what I came up with that maybe could work..
So basically, the command in cmd is of type EventCommand, but I want it to get the type "eventCommands[cmd.classTypeID].GetType()"
and use that to run the right class method.