0

I'm still new to C# and cannot wrap my head around this issue.

I have a two classes deriving from a generic class with T deriving from BackgroundWorker (see below). How can I have a field in another class that is able to hold either of the two derived classes and access the field with the derived BackgroundWorker? I need to be able to subscribe to the derived BackgroundWorker's events and issue e.g. CancelAsync command...

I have a generic class:

public class GenericClass<T> where T : BackgroundWorker
    {
        public T BgWorker;
    }

and derive two classes from it:

public class DerivedOne : GenericClass<BackgroundWorkerOne>
    { }

public class DerivedTwo : GenericClass<BackgroundWorkerTwo>
    { }

where:

public class BackgroundWorkerOne : BackgroundWorker
    { }

public class BackgroundWorkerOne : BackgroundWorker
    { }

However, how can I make a field/property in another class that is able to hold either DerivedOne or DerivedTwo depending on some other variable?

I have tried

public class AnotherClass
{
   public GenericClass<BackgroundWorker> Derived;

   public void DoSomething()
   {
      Derived = new DerivedOne();
   }
}

But I get the "Cannot implicitly convert type 'DerivedOne' to 'GenericClass<BackgroundWorker>'" error. Casting it

Derived = (GenericClass<BackgroundWorker>)new DerivedOne();

does not work either.

As mentioned, I would like to subscribe to the events in Derived.BgWorker regardless if the Derived is of type DerivedOne or DerivedTwo.

Is using generics here the best option? Or would another path (interface, shadowing or something else entirely) be a better solution?

Any help would be appreciated!

EDIT

I see that my approach, as has been pointed out in Cast Generic<Derived> to Generic<Base>, is not really feasible. Thank you for that clarification. The code I've shown above is only what I have tried so far, not necesarrily a fixed direction in which the code has to develop.

Furthermore, my question was more geared towards finding a way to access the BackgroundWorker (property with varying types in different classes) from the same base class.

What would be a suitable alternative to be able to access the BackgroundWorker (wheather BackroundWorkerOne or BackgroundWorkerTwo) property of the Derived property? Is there a possiblity to do so or should I rethink my concept?

stevan1986
  • 23
  • 6
  • 2
    when you alrteady know that `AnotherClass` depends on `DerivedOne`. why not just make the property of that specific type? Anyway you should learn about [covariance](https://learn.microsoft.com/dotnet/csharp/programming-guide/concepts/covariance-contravariance/). In Short only because two types have some inheritance doen't mean that generics also have. A `List` simply is not a `List`, or in your case a `DerivedOne` is *not* a `GenericClass`, but a `GeneroicClass`. – MakePeaceGreatAgain Mar 03 '23 at 10:13
  • Because it can depend on `DerivedTwo` just as well, depending on where in the process the whole program is. I want to have a "unified" property that always has access to the BackgroundWorker currently running. – stevan1986 Mar 03 '23 at 10:17

1 Answers1

1

Maybe covariance is what is missing in your code ? You can have this interface

public interface IGenericClass<out T> where T : BackgroundWorker
{
    T BackgroundWorker { get; }
}

Then you can use this interface like this

public class AnotherClass
{
   public IGenericClass<BackgroundWorker> Derived;

   public void DoSomething()
   {
      Derived = new DerivedOne();
   }
}

public class DerivedOne : IGenericClass<BackgroundWorkerOne>
{
    public BackgroundWorkerOne BackgroundWorker { get; }
}
Mad hatter
  • 569
  • 2
  • 11
  • Thank you, this compiles. However, I still don't know how to access the BackgroundWorker in `DerivedOne` or `DerivedTwo` as it is not a property (If I try to declare it as a property in the interface, I get the Invalid variance error (The type parameter 'T' must be invariantly valid on 'IGenericClass.BgWorker. 'T' is covariant.) Any suggestions to how to solve this? – stevan1986 Mar 03 '23 at 11:42
  • @stevan here you go – Mad hatter Mar 03 '23 at 12:25
  • @stevan1986, you just need to not have a setter in your interface – Mad hatter Mar 03 '23 at 12:33