简体   繁体   中英

How to create an abstract method with a parameter of type of implementing class

I have got a abstract class with an abstract method taking a parameter of the type of the implementing class. I can achieve this by generics like this:

abstract class Clazz<T>
{
   public abstract void CopyFrom(Clazz<T> source);
}

class MyClass : Clazz<MyClass>
{
  public override void CopyFrom(Clazz<MyClass>)
  {
    // implementation
  }
}

Unfortunately I need in one of the implementing classes a list of Clazz<T> elements. So how can I achieve this?

  • Of cause List<Clazz<T>> does not work.
  • List<Clazz<MyClass>> is too restrictive.
  • Removing the generics and the abstract method does work (my current solution), but this way I could forget to implement the CopyFrom() method in one of the implementing classes.

Edit: Here comes a more detailed example: I've got an abstract class:

abstract class Clazz<T>
{
    public abstract void CopyFrom(Clazz<T> source);
    // ...
}

And a derived class:

class MyDerivedClass : Clazz<MyDerivedClass >
{
    public string Text;
    private readonly List<MySubClass> _list = new List<MySubClass>();

    public override void CopyFrom(MyDerivedClass source)
    {
        Text = source.Text;
    }

    private List<Clazz> GetAllItems()
    {
        List<Clazz> list = new List<Clazz>();
        list.Add(this);
        list.AddRange(_list);
    }


    private class MySubClass : Clazz<MySubClass>
    {
        public int Number;

        public override void CopyFrom(MySubClass source)
        {
            Number = source.Number;
        }
    }
}

There are several other deriving classes, the GetAllItems() Method is only needed in MyDerivedClass .

You can make the respective method generic, too, and introduce a constraint that takes T into account. If I understand well what you want to achieve, you can do this:

abstract class Clazz<T>
{
   public abstract void CopyFrom(Clazz<T> source);

   public abstract void ProcessList<TDescendant>(List<TDescendant> list)
       where TDescendant : Clazz<T>;
}

class MyClass : Clazz<MyClass>
{
    public override void CopyFrom(Clazz<MyClass> source)
    {
        // implementation
    }

    public override void ProcessList<TDescendant>(List<TDescendant> list)
    {
        // implementation
    }
}

You can also easily include list processing in a descendant, like this:

class MyOtherClass : Clazz<MyOtherClass>
{
    public override void CopyFrom(Clazz<MyOtherClass> source)
    {
        // implementation
    }

    // this list processing is inherited
    public override void ProcessList<TDescendant>(List<TDescendant> list)
    {
        // implementation
    }

    // this list processing is specific to this descendant only
    public void ProcessMyClassList<TDescendant>(List<TDescendant> list)
        where TDescendant : Clazz<TMyClass>
    {
        // implementation
    }
}

Then use can declare a descendant of MyClass , which in turn is a Clazz<T> , T being MyClass :

class MyDescendant : MyClass
{ 
}

The following works:

List<MyDescendant> list = new List<MyDescendant>();
new MyClass().ProcessList(list);

In case of MyOtherClass , the situation is a little bit different. ProcessMyClassList accepts a list of Clazz<T> or its descendants; however, not those related to MyOtherClass but to the good-ol' MyClass . This code works:

List<MyDescendant> list = new List<MyDescendant>();
new MyOtherClass().ProcessMyClassList(list); // this works

But the following won't compile:

List<MyOtherClass> list = new List<MyOtherClass>();
new MyOtherClass().ProcessList(list);        // this works
new MyOtherClass().ProcessMyClassList(list); // this doesn't

would this suffice? without more details it is hard to tell.

interface ICopyMaker
{
    void CopyFrom(ICopyMaker source);
}

abstract class Clazz<T> : ICopyMaker
{
   public abstract void CopyFrom(Clazz<T> source);

   void ICopyMaker.CopyFrom(ICopyMaker source)
   {
       var src = source as Clazz<T>;
       if (src == null) return; // know how to copy only from the instances of the same type

       CopyFrom(src);
   }
}

class MyClass : Clazz<MyClass>
{
    private List<ICopyMaker> _list = new List<ICopyMaker>();

    public override void CopyFrom(Clazz<MyClass> c)
    {
    //implementation
    }
}

Thank's everyone for your answers, but I think I have figured out a solution I can live with: I will remove the generics and add a typecheck, like in the solution from anikiforov:

Abstract class:

abstract class Clazz
{
   public abstract void CopyFrom(Clazz source);
}

And the derived class:

class MyDerivedClass : Clazz
{
    public string Text;
    private List<MyNestedClass> _list;

    public override void CopyFrom(Clazz source)
    {
        var src = source as MyDerivedClass;
        if (src == null) return;
        Text = src.Text;
    }

    public List<Clazz> GetAllItems()
    {
        var list = new List<Clazz>();
        list.Add(this);
        list.AddRange(_list);
        return list;
    }

    class MyNestedClass : Clazz
    {
        public int Number;
        public override void CopyFrom(Clazz source)
        {
            var src = source as MyNestedClass;
            if (src == null) return;
            Number = src.Number;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM