Understanding Variance (Contravariance) - c#

I'm trying to understand how Variance works. I have created a IRegistry interface which supports a Contravarint TDomainEvent and a Contravariant TDomainContraVariant. The thing is that the TDomainEvent extends a IDomainEvent and the TDomainContraVariant extends an IDomainEventHandler<TDomainEvent>.
For some reason I get errors saying that it is not possible to convert TDomainContraVariant to IDomainEventHandler<IDomainEvent>, which should be possible as a TDomainEvent extends an IDomainEvent.
using System;
using System.Collections.Generic;
public interface IDomainEvent {}
public class ProductSetCreatedEvent : IDomainEvent {}
public class VersionCreatedEvent : IDomainEvent {}
public class ProductSetCreatedEventHandler : IDomainEventHandler<ProductSetCreatedEvent> {}
public class VersionCreatedEventHandler : IDomainEventHandler<VersionCreatedEvent> {}
public interface IDomainEventHandler<in TDomainEvent> where TDomainEvent : IDomainEvent {}
public interface IRegistry<in TDomainEvent, in TDomainContraVariant>
where TDomainEvent : IDomainEvent
where TDomainContraVariant : IDomainEventHandler<TDomainEvent>
{
void Add(TDomainContraVariant element);
}
public class Registry<TDomainEvent, TDomainContraVariant> : IRegistry<TDomainEvent, TDomainContraVariant>
where TDomainEvent : IDomainEvent
where TDomainContraVariant : IDomainEventHandler<TDomainEvent>
{
private IList<IDomainEventHandler<IDomainEvent>> list;
public Registry()
{
this.list = new List<IDomainEventHandler<IDomainEvent>>();
}
public void Add(TDomainContraVariant element)
{
this.list.Add(element);
}
public IList<IDomainEventHandler<IDomainEvent>> Get()
{
return this.list;
}
}
public class Program
{
private static Registry<IDomainEvent, IDomainEventHandler<IDomainEvent>> list = new Registry<IDomainEvent, IDomainEventHandler<IDomainEvent>>();
public static void Main()
{
IDomainEventHandler<ProductSetCreatedEvent> eventHandler = new ProductSetCreatedEventHandler();
AddToRegistry<ProductSetCreatedEvent, IDomainEventHandler<ProductSetCreatedEvent>>(eventHandler);
}
public static void AddToRegistry<TDomainEvent, TDomainContraVariant>(TDomainContraVariant cesto)
where TDomainEvent : IDomainEvent
where TDomainContraVariant : IDomainEventHandler<TDomainEvent>
{
list.Add(cesto);
}
}

Related

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

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.
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.
Why
public class UIScreen<T> where T : IScreenController
{
public void Open(T controller) { }
}
and not simply
public class UIScreen
{
public void Open(IScreenController controller) { }
}

Implicit Conversion with Generics

I'm essentially trying to upcast an object but I don't know how to deal with the generics. Below is a super-contrived example but it illustrated a situation I'm working with. Perhaps I need an implicit operator but I'm not sure what that would look like in this scenario.
using System;
using System.Collections.Generic;
class MainClass {
public static void Main (string[] args) {
var cats = new Dictionary<string, IAnimal<ICat>>()
{
{ "paws", new Tabby() },
{ "teeth", new MountainLion() }
};
foreach (var cat in cats)
{
cat.Value.talk();
}
}
public interface IAnimal<T> where T : ICat
{
void talk();
}
public interface ICat
{
}
public class HouseCat : ICat
{
}
public class BigCat : ICat
{
}
public class MountainLion : IAnimal<BigCat>
{
public void talk() {
Console.WriteLine("Rawr!");
}
}
public class Tabby : IAnimal<HouseCat>
{
public void talk() {
Console.WriteLine("Meow");
}
}
}
Thanks to #kalten I arrived at this solution:
public interface Animal<out T> where T : Cat
You can see it working here: https://repl.it/#austinrr/FlippantLonelyTab#main.cs

Using base class and base interface in C#

I am reshaping an entire system that does not use base classes and base interfaces.
My idea to do so is to extract all the common methods to a base classes and base interfaces.
So basically, we would have:
A base class SomeClassBase implementing an interface ISomeClassBase
A derived class SomeClassDerived implementing ISomeClassDerived (this interface deriving from ISomeClassBase)
Now the problem, how can I instantiate "_mySession" in the derived class (which has a different cast than in the base class), while preserving all the methods from the base class:
public class SomeClassBase : ISomeClassBase
{
public IMySessionBase _mySession = MySession.Instance();
public SomeClassBase ()
{
_mySession.connect(); // Needed??
}
public void doSomething()
{
_mySession.doSomething();
}
}
public class SomeClassDerived : SomeClassBase, ISomeClassDerived
{
public IMySessionDerived _mySession = MySession.Instance();
public SomeClassDerived ()
{
_mySession.connect();
}
public void doSomethingElse()
{
_mySession.doSomethingElse();
}
}
One more thing, IMySessionDerived implements IMySessionBase.
Do not redefine _mySession Let it come from base class.
However in you Derived class you can still reassign.
public class SomeClassDerived : SomeClassBase, ISomeClassDerived
{
public SomeClassDerived ()
{
_mySession = MySession.Instance(); //Declaration comes from base class automatically
_mySession.connect();
}
public void doSomethingElse()
{
_mySession.doSomethingElse();
}
}
If your IMySessionBase and IMySessionDerived are following Hierarchy, it should work. But in some rare cases, You might end up getting into a DoubleDispatchProblem.
As Pointed out in commens, If you want to do something from IMySessionDerived you can add a Property.
public class SomeClassDerived : SomeClassBase, ISomeClassDerived
{
IMySessionDerived _derivedSessionAccessor=> _mySession as IMySessionDerived;
}
Update: To fix the exact design problem here,
Instead of deriving from the base class, have it as a field. And inherit from interface. So Instead of doing above approach,
do like,
public class SomeClassBase : ISomeClassBase
{
public IMySessionBase _mySession ;
public SomeClassBase ( IMySessionBase session)
{
_mySession=session;
_mySession.connect(); // Needed??
}
public void doSomething()
{
_mySession.doSomething();
}
}
public class SomeClassDerived : , ISomeClassDerived
{
public IMySessionDerived _mySession = MySession.Instance();
private SomeClassBase _baseClassInstance;
public SomeClassDerived ()
{
_baseClassInstance=new SomeClassBase(_mySession);
//_mySession.connect();
}
public void doSomethingElse()
{
_baseClassInstance.doSomethingElse();
}
}
Pasting #Selvin answer instead of the link buried in the comments:
The trick here is to use the keyword "base()"
using System;
using System.Runtime.CompilerServices;
public class Program
{
public static void Main()
{
var o1 = new O1();
o1.DS1();
var o2 = new O2();
o2.DS1();
o2.DS2();
}
public class Session1
{
protected readonly Type ownerType;
public Session1(Type type)
{
ownerType = type;
}
public virtual void DS1([CallerMemberName] string functionName = "")
{
Console.WriteLine(ownerType.Name + ":" + GetType().Name + ":" + functionName);
}
}
public class Session2 : Session1
{
public Session2(Type type):base(type) { }
public virtual void DS2([CallerMemberName] string functionName = "")
{
Console.WriteLine(ownerType.Name + ":" + GetType().Name + ":" + functionName);
}
}
public class O1
{
private readonly Session1 t;
public O1() : this(new Session1(typeof(O1))) { }
protected O1(Session1 t)
{
this.t = t;
}
public void DS1()
{
t.DS1();
}
}
public class O2 : O1
{
private readonly Session2 t;
public O2() : this(new Session2(typeof(O2))) { }
protected O2(Session2 t) : base(t)
{
this.t = t;
}
public void DS2()
{
t.DS2();
}
}
}

Creational pattern for generic objects

could someone please help with the best way of returning the concrete implementation in the following scenarios. Say I have:
public interface IThing<TInput> where TInput : RequestBase
{
string Process(T input);
}
And then multiple implementations:
public class Thing1<T> : IThing<T> where T : ReqThing1
public class Thing2<T> : IThing<T> where T : ReqThing2
In my calling class what is the best way of wrapping the construction of those classes and returning the IThing that I want in a clean, testable way? Thanks
I don't quite understand what you want, but here's an idea:
public abstract class RequestBase
{
}
public class ReqThing1 : RequestBase
{
}
public class ReqThing2 : RequestBase
{
}
public interface IThing<T> where T : RequestBase
{
string Process(T input);
}
public class Thing1 : IThing<ReqThing1>
{
public string Process(ReqThing1 input)
{
throw new System.NotImplementedException();
}
}
public class Thing2 : IThing<ReqThing2>
{
public string Process(ReqThing2 input)
{
throw new System.NotImplementedException();
}
}
public class Program
{
public static void Main(string[] args)
{
var thing1 = new Thing1();
var thing2 = new Thing2();
}
}

Generic method override c# an explicit conversion exists (are you missing a cast?) error

public class Base
{
}
public class Rabbit : Base
{
}
public abstract class OO
{
public abstract ICollection<T> Test<T>() where T : Base;
}
public class LOL : OO
{
public override ICollection<T> Test<T>()
{
return new Collection<Rabbit>();
}
}
This formation of class gives following error.
'System.Collections.ObjectModel.Collection' to 'System.Collections.Generic.ICollection'. An explicit conversion exists (are you missing a cast?)
Any idea how to fix this?
Try this:
public class LOL : OO
{
public override ICollection<T> Test<T>()
{
return (ICollection<T>) new Collection<Rabbit>();
}
}
public class Base
{
}
public class Rabbit : Base
{
}
public abstract class OO
{
public abstract ICollection<T> Test<T>() where T : Base;
}
public class LOL : OO
{
public override ICollection<T> Test<T>()
{
return new Collection<T>();
}
}
or
public class Base
{
}
public class Rabbit : Base
{
}
public abstract class OO
{
public abstract ICollection<T> Test<T>() where T : Base;
}
public class LOL : OO
{
public override ICollection<T> Test<T>()
{
return new Collection<Rabbit>() as ICollection<T>;
}
}

Categories