Cruces
Cruces

Reputation: 3129

How do you run a child class' overriden method when using generics in c#?

I have a class hierarchy like this:

   public abstract class BaseObject { 
        //even though this does not have abstract methods I declare it as abstract because I do not want it to be initialized
        ....
        public void save(Connection con) {
           con.InsertOrReplace(this);
        }
        ....
   }

   public abstract CheckedDataObject : BaseDataObject {
        ....
        public abstract new void save(Connection con);
   }

These two classes are used by my data objects, some of them simply need to be saved, others have to run checks before being saved, and since the checks are different the save method in CheckedDataObject is abstract

for example:

public class Father : BaseDataObject {

}

this just needs to be saved , BaseDataObject's save works correctly but:

public class Child : CheckedDataObject {
     ....
     public override void save(Connection con) {
        //do checks here to see if it is correct, if not throw an exception
        con.Insert(this);
     }
     ....


}

My problem is when I use a generic method to save a list of objects (some may be father, some may be children) like this:

public void save_all<T>(Connection con, List<T> items) where T: BaseDataObject {
    foreach (int idx = items.Count - 1 ; i >= 0 ; i--) {
        //initializations and checks go here
        items[i].save(con);
    }
}

The problem is that save() always calls BaseDataObject's save even when the item being parsed is a CheckedDataObject

How can I alter my method so that it will call the correct save method?

thanks in advance for any help you can provide

Upvotes: 0

Views: 89

Answers (4)

Kricke242
Kricke242

Reputation: 59

To answer your question, don't use new, use override, and declare the function in the base class virtual.

  public abstract class BaseObject { 
        //even though this does not have abstract methods I declare it as abstract because I do not want it to be initialized
        ....
        public virtual void save(Connection con) {
           con.InsertOrReplace(this);
        }
        ....    }

   public abstract CheckedDataObject : BaseDataObject {
        ....
        public override void save(Connection con);    }

Second, perhaps you should use interfaces instead of abstract classes?

Third, is BaseObject som kind of model? If so, perhaps you shold put saving in an other (e.g. repository) class. (Single responsibility principle).

Upvotes: 0

Alex
Alex

Reputation: 322

So, there is a simple solution: cast to CheckedDataObject. But if I were you I would prefer to avoid using this class hierarchy .

public void save_all<T>(Connection con, List<T> items) where T: BaseDataObject {
foreach (int idx = items.Count - 1 ; i >= 0 ; i--) {
    //initializations and checks go here
    var cdo = items[i] as CheckedDataObject;
    if (cdo != null)
        cdo.save(con);
    else
        items[i].save(con);
}}

Upvotes: -1

user3292642
user3292642

Reputation: 761

I think what your looking for is simply one base class with a virtual method like this:

  public abstract class BaseObject
  {
     public virtual void Save(Connection con)
     {
         con.InsertOrReplace(this);
     }
  }

  public class Father : BaseObject
  {
      public override void Save()
      {
       // no checks needed?
       base.Save();
      }
  }

  public class Child : BaseObject
  {
    public override void Save()
    {
     //do checks here to see if it is correct, if not throw an exception
     base.Save();
    }
  }

What is the use of CheckedDataObject? I dont see it.

If you have a Collections of BaseObject now and call the Save method, the overridden method of the derived class will be called.

Upvotes: 0

Juan Ignacio Cornet
Juan Ignacio Cornet

Reputation: 239

Check this https://blogs.msdn.microsoft.com/csharpfaq/2004/03/12/whats-the-difference-between-override-and-new/

I guess that your problem comes from the point that you're using new in CheckedDataObject.Save, so when you iterate and your condition is where T: BaseDataObject, the called method will be always BaseObject.save or it's overrides.

Try to use override instead new in CheckedDataObject

Upvotes: 3

Related Questions