Home > database >  possible to do Func<T1>(T2 param) where T1: Foo<T> and T2 is the T in Foo<T>?
possible to do Func<T1>(T2 param) where T1: Foo<T> and T2 is the T in Foo<T>?

Time:05-03

I'm trying to create a screen manager for a game where I should be able to open the screens through said manager using a controller classes

I have this:

public interface IScreenController { }

public class UIScreen<T> where T : IScreenController
{
  public void Open(T controller) { }
}

public class ScreenManager
{
   public T GetScreen<T>()
   {
    //some screen getter method here
   }

   public void Open<T, J>(J controller) where T : UIScreen<J> where J : IScreenController
   {
     var screen = GetScreen<T>();
     screen.Open(controller);
   }
}

public class MyScreenController : IScreenController { }

public class OtherScreenController: IScreenController { };

public class MyScreen : UIScreen<MyScreenController> { }

and currently, i can make it work with this:

public class SomeClass
{
   public ScreenManager Manager;

   public void SomeMethod()
   {
      Manager.Open<MyScreen, MyScreenController>(new MyScreenController());
   }
}

is it possible to do only Manager.Open<MyScreen>(Controller) while keeping enforcing the parameter? I know i can do Open<T>(IScreenController controller) where T: UIScreen, but that would allow me to put any screen controller as a parameter.

CodePudding user response:

I think you're setting yourself up for a world of heartache here trying to use generics like this. Once you're trying to constrain the types you should begin to ask yourself if it's better to just provide function overloads.

I know you've given us abbreviated code, but instead of:

public interface IScreenController { }

public class UIScreen<T> where T : IScreenController
{
    public void Open(T controller) { }
}

Why not just put the Open function in the interface? Then you can ditch UIScreen altogether, or if you really need it to implement some functionality that would make inheritance worthwhile then you could make UIScreen an abstract class, like:

public interface IScreenController
{ 
    public void Open(IScreenController controller) { }
}

public abstract class UIScreen : IScreenController
{
    public void Open(IScreenController controller) { // functionality goes here }
}

Another thing you could do is to specify the type as a constructor in your inheritance chain, like instead of what you wrote here:

public class UIScreen<T> where T : IScreenController
{
  public void Open(T controller) { }
}

public class MyScreenController : IScreenController { }

public class MyScreen : UIScreen<MyScreenController> { }

You could make UIScreen take an IScreenController as part of the constructor argument, and you could pass that when a subclass is constructed, like the following:

public class UIScreen
{
    protected IScreenController screenController;
    public UIScreen(IScreenController screenController)
    { 
        this.screenController = screenController;
    }
}

public class MyScreenController : IScreenController { }

public class MyScreen : UIScreen
{
    public MyScreen() : base(new MyScreenController()) { }
}

then you can do whatever needs doing from your protected IScreenController.

CodePudding user response:

Why

public class UIScreen<T> where T : IScreenController
{
  public void Open(T controller) { }
}

and not simply

public class UIScreen 
{
  public void Open(IScreenController controller) { }
}
  • Related