Invariant inheritance problem - c#

I'm trying to implement a strategy pattern to allow me to allow me to apply some "benefit" to an "account". In the code below, I can't add my implementation of an interface to a dictionary expecting the interface. I think it's some kind of contravariance problem, but it feels like I should be able to do this:
EDIT:
Since the answer seems to be that it's just not possible, any suggestions on how to achieve what I'm going for here?
void Main()
{
var provider = new BenefitStrategyProvider();
var freeBenefit = new FreeBenefit();
var strategy = provider.GetStrategy(freeBenefit);
strategy.ApplyBenefit(freeBenefit, new Account());
}
public class BenefitStrategyProvider
{
private Dictionary<Type, IBenefitStrategy<BenefitBase>> _strategies = new Dictionary<Type, IBenefitStrategy<BenefitBase>>();
public BenefitStrategyProvider()
{
/* Why can't I add this? */
_strategies.Add(typeof(FreeBenefit), new FreeBenefitStrategy());
}
public IBenefitStrategy<BenefitBase> GetStrategy(BenefitBase benefit)
{
return _strategies[benefit.GetType()];
}
}
public class Account {}
public abstract class BenefitBase
{
public string BenefitName {get;set;}
}
public class FreeBenefit : BenefitBase {}
public interface IBenefitStrategy<T> where T: BenefitBase
{
void ApplyBenefit(T benefit, Account account);
}
public class FreeBenefitStrategy : IBenefitStrategy<FreeBenefit>
{
public void ApplyBenefit(FreeBenefit benefit, Account account)
{
Console.WriteLine("Free Benefit applied");
}
}

EDITED - The formatting engine had removed everything in <angled brackets>, which made it rather impossible to understand. Sorry if this was confusing!
FreeBenefitStrategy implements IBenefitStrategy<FreeBenefit>. It can apply only FreeBenefits, not any other kind of benefit. It is not an IBenefitStrategy<BenefitBase>, so you can't put it in a collection of those. Logically, IBenefiteStrategy could be contravariant in BenefitBase, but this doesn't help you here - an IBenefitStrategy<BenefitBase> claims to be able to apply all kinds of benefits, so an IBenefitStrategy<BenefitBase> is-an IBenefitStrategy<FreeBenefit>, but the converse is not true - an IBenefitStrategy<FreeBenefit> cannot apply any BenefitBase.
I don't think there's any way to have a heterogenous collection like you want without using type-casting. If you think about it, there's no method that you can invoke on both an IBenefitStrategy<FreeBenefit> and an IBenefitStrategy<ExpensiveBenefit> beyond those that they share from object, so it makes sense that a variable of type object is the only thing that can point to either. If you want to keep them in the same dictionary, you'll need to make it a Dictionary<Type, object>. You could change GetStrategy to be generic and apply appropriate type-casting, but do be careful when looking up your dictionary - think what will happen if the object passed in is of a sub-class of FreeBenefit.

See: Covariance and Contravariance FAQ
How can I create variant generic interfaces and delegates myself?
The out keyword marks a type parameter as covariant, and the in keyword marks it as contravariant. The two most important rules to remember:
You can mark a generic type parameter as covariant if it is used only as a method return type and is not used as a type of formal method parameters.
And vice versa, you can mark a type as contravariant if it is used only as a type of formal method parameters and not used as a method return type.

You need to add out T to your interface:
public interface IBenefitStrategy<in T>

Related

'Strongly Typed' Generic Collections that hold any <T> of a given Interface/Class

Is it possible to declare a generic collection to hold only objects implementing a generic Interface with any <T>?
My question burns down to: If I want to/have to store objects implementing a generic interface, is there a better way to express that fact than using a non generic collection or (generic of <Object>).
Example:
// An example Generic Interface
interface ISyncInterface<T>
{
Task DoSync();
IEnumerable<T> NewItems { get; }
}
// a manager-class that registers different classes implementing
// the generic interface.
// The code works - can it be done better?
class Manager
{
private List<Object> _services = new List<Object>(); // <- works but is basically non generic
// however the RegisterService() ensures that only correct types can be added.
// would like to have something like below to indicate the Interface-Type
// however: this would only allow _services2.Add to hold types of ISyncInterface<Object>
// - ISyncInterface<ServiceA_DTO> would fail.
private List<ISyncInterface<Object>> _services2 = new List<ISyncInterface<Object>>();
void RegisterService<T, U>(T service)
where T : ISyncInterface<U>
{
_services.Add(service); // <- works e.g. for SyncServiceA
// _services2.Add(service); // <- FAILS for SyncServiceA - no conversion
// _services2.Add((ISyncInterface<Object>) service); // <- FAILS also - no explicit cast
}
}
// SETUP - The classes used above. Just to clarify.
class ServiceA_DTO { }
class ServiceB_DTO { }
class SyncServiceA : ISyncInterface<ServiceA_DTO>
{
public Task DoSync() {}
public IEnumerable<ServiceA_DTO> NewItems { get; }
}
class SyncServiceB : ISyncInterface<ServiceB_DTO>
{
public Task DoSync() {}
public IEnumerable<ServiceB_DTO> NewItems { get; }
}
Is this possible at all? Any advice is highly appreciated!
Update: New, more verbose code to clarify the problem.
Below there was a suggestion to base the generic interface on an non generic one. But as a consequence all implementing classes of the generic interface would have to implement the non generic methods, properties etc. - or is there a way around it?
Thanks for your input!
Is it possible to declare a generic collection to hold only objects implementing a generic interface instantiated with any T?
Short answer: no.
Longer answer: no, because that is not useful.
Let's consider a simple generic interface:
interface I<T> { T Get(); }
And a bunch of objects that implement it:
class Lion : I<Lion>
{
public Lion Get() => this;
}
class TaxPolicyFactory : I<TaxPolicy>
{
public TaxPolicy Get() => new TaxPolicy();
}
class Door: I<Doorknob>
{
public Doorknob Get() => this.doorknob;
...
}
OK, now suppose you have a List<I<ANYTHING>> like you want:
var list = new List<I<???>> { new TaxPolicyFactory(), new Lion(), new Door() };
You've got a list with a tax policy factory, a lion and a door in it. Those types have nothing in common with each other; there's no operation you can perform on each of those objects. Even if you could call Get on each of them, then you'd have a sequence with a tax policy, a lion and a doorknob in it, and what are you going to do with that?
Nothing, that's what. The constraint "implements interface I<T> for any T" is simply not a useful constraint in C#, so there is no way to express it.
It sounds like you have an "XY" problem. That is a problem where you have a bad solution in mind, and now you are asking questions about your bad solution. Ask us a question about the real problem you have, not the bad idea you've got for its solution. What's the real problem?
UPDATE: With the new information in the question it is now much more clear. The feature you want is called generic interface covariance, which was my favourite feature for C# 4.
If you update your interface definition to
interface ISyncInterface<out T> { ... }
then you can use an ISyncInterface<String> in a context where an ISyncInterface<Object> is expected. For example, you could put an ISyncInterface<Giraffe> into a List<ISyncInterface<Animal>> or whatever.
However you are required to ensure that your interface definition only uses T in a covariantly valid position. Your interface is valid as stated, but if for example you ever want to add a method void M(T t); to your interface, it will no longer be covariantly valid. The "out" is a mnemonic telling you that T can only be used as output of methods. Since IEnumerable<T> is also covariantly valid, it's fine; there are no inputs of T in an IEnumerable<T>.
Also, variance only works with generic interfaces and delegates, and the varying types must be reference types. You can't put an ISyncInterface<int> into a List<ISyncInterface<Object>> because int is not a reference type.
There are many posts on SO about covariance and contravariance; you should also read the Microsoft documentation. It can be a confusing feature. If you're interested in the historical details of how we designed and implemented the feature, see my blog.
Perhaps you can try something like this:
public interface MyInterface
{//methods common to all types
void FirstMethod();
}
public interface MyInterface<T> : MyInterface
{//methods specific to a type
void FirstMethod(T parameter);
}
public class MyClassThatHandlesAllInterfaces
{
private List<MyInterface> _allInterfacesT; //first interface in the chain
public void AddInterface<T>(MyInterface<T> ifToAdd)
{
_allInterfacesT.Add(ifToAdd); // <- this is what I'd like to do
}
}
I use this pattern quite often. Because I do not know all the details about your scenario it might not be suitable for you.
But it might help other people searching google.

Can I define/constrain a member as implementing two interfaces, without generics?

The following code shows what I would like to do; that is, I would like to constrain anObject, so that it can be used as a parameter to various methods with use IInterfaceOne or IInterfaceTwo, where neither inherits from the other.
public interface IInterfaceOne { }
public interface IInterfaceTwo { }
public class Implementation : IInterfaceOne, IInterfaceTwo
{
}
public interface IInterfaceOneAndTwo : IInterfaceOne, IInterfaceTwo { }
public class UsingImplementation
{
IInterfaceOneAndTwo anObject = (IInterfaceOneAndTwo)(new Implementation()); //fails because Implementation doesnt acctually implement IInterfaceOneAndTwo
}
This example fails however as IInterfaceOneAndTwo is an interface in its own right, and Implementation does not implement it.
I know if I used generics I could constrain them, but I am wondering, if there is a way to do this without generics?
Is there a way to say anObject shall implement IInterfaceOne and IInterfaceTwo, without using IInterfaceOneAndTwo?
Not the way you have it currently. Only generic constraints have that ability.
You could rewrite it to use generics:
public class UsingImplementation<T>
where T : IInterface1, IInterface2, new()
{
T anObject = new T();
void SomeMethod() {
anObject.MethodFromInterface1();
}
}
You can also have generic methods, not only generic classes
public void DoSomething<T>(T value)
where T : IInterface1, IInterface2
{
value.DoInterface1Things();
value.DoInterface2Things();
}
Or
public void DoSomething<T>()
where T : IInterface1, IInterface2, new()
{
T anObject = new T();
}
You can't do that in C# without generics but there is an alternative workaround to solve the problem without generics that was not mentioned here and might fit for you. This style is often used together with the IoC principle. You could inject the same object twice. Let me change your sample quite a bit...
public interface IInterfaceOne { void Hello(); }
public interface IInterfaceTwo { void World(); }
public class Implementation : IInterfaceOne, IInterfaceTwo
{
public void Hello() { };
public void World() { };
}
public class UsingImplementation
{
private readonly IInterfaceOne one;
private readonly IInterfaceTwo two;
public UsingImplentation(IInterfaceOne one, IInterfaceTwo two)
{
this.one = one;
this.two = two;
}
// do the stuff you want to do with an IInterfaceOne using field one
public DoSomeThingWithOne() { one.Hello(); }
// do the stuff you want to do with an IInterfaceTwo using field two
public DoSomeThingWithTwo() { two.World(); }
}
Then you could wire up the things this way:
var oneAndTwo = new Implementation();
var a = new UsingImplementation(oneAndTwo, oneAndTwo);
// operates on the first param (which is the same as the second)
a.DoSomeThingWithOne();
// operates on the second param (which is the same as the first)
a.DoSomeThingWithTwo();
Have a look for IoC principle (Inversion of Control) and Dependency Injection and you'll find more solutions similiar to this one.
This way you don't need to create an extra Interface combining InterfaceOne and InterfaceTwo, two.
"Incoming" generic class parameters and generic method parameters can combine types, but there is no facility for variables or fields to represent "composite" types. Further, in order to pass an object to a parameter of a generic type which combines multiple constraints, the object must be cast to a type which in fact implements all of those constraints. This can be difficult.
For example, suppose class Foo and Bar both implement Intf1 and Intf2. One wishes to write a function AddToList<T>(thing as T) where T:Intf1,Intf2. Such a function will perfectly happily accept objects of type Foo or Bar. Suppose, however, one wishes to use such a function to add all objects to the same list (which might be a mix of Foo, Bar, and any number of other types that also happen to implement Intf1 and Intf2) and then later pass those objects to a function whose parameter is likewise constrained to implement both Intf1 and Intf2. One could cast to Foo any object which happened to be a Foo, and cast to Bar any object which happened to be a Bar, but if other types are written which also handle Intf1 and Intf2, it would be difficult to deal with them.
It is possible to solve the problem, somewhat awkwardly, without using Reflection or other such tricks. Define an interface IActUpon<Base1, Base2> with a method ActUpon<thingType>ActUpon(thingType thing) where thingType: Base1, Base2. Implementations of such a method will be able to pass parameter thing to other methods requiring generic method parameter constrained to Base1 and Base2. The biggest difficulties with such an approach are that one must write separate code for each possible number of constraints, and that in many places where one would have used a lambda expression one will instead have to write an implementation of IActUpon....
If this is desirable then there has to be a logical connection between IInterfaceOne and IInterfaceTwo and the implementing class should implement the combined interface:
class Implementation : IInterfaceOneAndTwo { ... }
If this is not possible, because it's not (all) your code then you may have to rethink the UsingImplementation. It simply doesn't fit the available surface.

Inferring C# Generic Type of Subclass

I have a generic class Proxy<T>, and I want to write another generic class with its type parameter being a Proxy.
I want to write:
public class MyClass<U> where U : Proxy<T>
but the compiler reports The type or namespace name T could not be found.
A solution I've found is to declare it like this:
public class MyClass<U, T> where U : Proxy<T>
but this seems clumsy as the client will have to declare two type parameters, like this:
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass> { ... }
and then in a client somewhere:
var proxyWrapper = new MyClass<SomeProxy, SomeClass>();
How can I do this without having to have two generic types on MyClass. After all, if we know the first is SomeProxy, it should follow that the second is SomeClass.
Maybe something like this would do the job, too?
class Test<T> {
public Test(Proxy<T> proxy) { this.MyProxy = proxy; }
public Proxy<T> MyProxy { get; private set; }
}
Sorry, you just can't do this in C# without having MyClass generic on both types (unless you want to use reflection to create instances of it.)
You can have an interface IMyClass<SomeProxy> and a factory method that creates and returns an instance of MyClass<SomeProxy, SomeClass>. You may need to create the instance using Reflection.
I have a code example here of a similar situation: the end user only cares about a single type parameter, but the implementation needs to have two. In my example, I don't have to use Reflection to create the instance, but it sounds like you may need to.
What you're trying to do is possible using compile-time constructs such as C++ templates, but not run-time constructs such as C# generics.
If you want T to remain generic in Myclass, then the MyClass instance still needs to resolve all internally used generic types and you HAVE TO declare it somewhere. The way to go is the verbose way you mentioned:
public class MyClass<U, T> where U : Proxy<T>
If you don't care about the generic type T in MyClass then create interface and use it instead:
public interface IProxy { ... }
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass>, IProxy { ... }
public class MyClass<U> where U : IProxy
and then in a client somewhere:
var proxyWrapper = new MyClass<SomeProxy>();
But do note that you cannot use type T in your interface declaration and Type U is now more general then before.
It turns out that all of the SomeProxy classes I want to deal with actually just override one method of Proxy<T> which has the signature:
T LoadInternal(Identifier id)
So, what I've done is created an internal class inside MyClass which takes a Func<Identifier, T> in its constructor. I can then pass a Func<Identifier, T> as a parameter to the constructor of MyClass and use my subclass in place of SomeProxy.
Seems a bit convoluted, but it works for me. To summarise, I now have:
public class MyClass<T>{
private SomeProxy theProxy;
public MyClass(Func<Identifier, T> loadDelegate){
theProxy = new SomeProxy(loadDelegate);
}
/* Other methods here */
class SomeProxy : Proxy<T>{
private Func<Identifier, T> m_loadInternal;
public SomeProxy(Func<Identifier, T> loadInternal){
m_loadInternal = loadInternal;
}
protected override T LoadInternal(Identifier id){
return m_loadInternal(id);
}
}
}
So, from client code, instead of writing a class which extends Proxy and then overriding LoadInternal in that class, I just create MyClass using:
var myClass = new MyClass<T>(x => CodeWhichReturnsT());
How can I do this without having to have two generic types on MyClass. After all, if we know the first is SomeProxy, it should follow that the second is SomeClass.
Although you seem to have found an answer to the main part of the question, I figured I'd offer my understanding about this part. It sounds like you wish you could do something like this:
class Proxy<T>
{
T Value { get; set; }
}
class MyClass<U> where U : Proxy<> { }
and have the compiler fill in the Proxy type parameter when you provide U. Since you have declared U as inheriting from Proxy, you must intend to use one of the methods on Proxy, that probably use the T parameter, like so:
class MyClass<U> where U : Proxy<>
{
void SomeMethod(U parameter)
{
var local = parameter.Value;
//more code here...
}
}
Now, what is the compiler supposed to infer for local here? This is the main problem I see that makes such a feature, if possible, hard to implement. If you don't want to use any methods that use the generic type of Proxy, you could instead make a non-generic base class and use that for U and sidestep the entire problem.
I am not a compiler writer, but a couple possibilities of how this could be dealt with come to mind. It could just say object (or whatever other restriction you put on the type parameter in Proxy), but that doesn't seem quite right or quite what normal generics seem to do. This would also require the CLR to allow open generic types as a constraint on the generic parameter, which I doubt it does. The other option I could see is for the type to actually have the second type parameter, and the compiler to give you syntactic sugar to make it easier.
Any way you go, this feature seems like a lot of work for a little benefit in what is probably a rare scenario, thus not likely to make the cut to get implemented.

Is it possible to make "this type" for generics in C#?

Kind of theoretical question. Quite long so feel free to skip if you are not in the mood for theory.
Imagine that you have two classes, one inherited from another. The base class is generic and has a method that in the closed type must return some instance of this closed type.
Like this (note ??? in text):
public class Adapter<T>
{
public virtual ??? DoSomething()
{
...
}
}
public class AdaptedString : Adapter<String>
{
public override AdaptedString DoSomething()
{
...
}
}
I can't do it because there is no way to refer to a closed type that will be derived from a generic type. (Sorry for broken language, just don't know how to express it.) There is no keyword to set in place of ??? to specify that this method will return instance of type that would be derived from this generic type.
Instead, I can use a workaround of explicitly passing the type name to the generic base. But it looks redundant.
public class Adapter<TThis,T>
{
public virtual TThis DoSomething()
{
...
}
}
public class AdaptedString : Adapter<AdaptedString,String>
{
public override AdaptedString DoSomething()
{
...
}
}
And if in the base class I need to access members of TThis instance, I have to add a constraint. This time it looks ugly - note the constraint:
public class Adapter<TThis,T>
where TThis : Adapter<TThis, T>
{
protected int _field;
...
public bool Compare( TThis obj )
{
return _field == obj._field;
}
}
public class AdaptedString : Adapter<AdaptedString,String>
{
...
}
Yes, it is all working, but it would look better if I can simply use some keyword instead of ??? in first code fragment. Something like "thistype".
How do you think will it work? Is it useful? Or maybe this is just plain stupid?
There's nothing which makes this pattern easier, and in fact the pattern isn't quite bulletproof anyway - because you can have:
class TypeA : Adapter<TypeA, string>
class TypeB : Adapter<TypeA, string> // Bug!
The second line here is entirely legal - TypeA is a valid type argument for the TThis type parameter, even though it's not what we wanted. Basically the type system doesn't let us express the concept of "T must be this type."
I disagree with those who say it's a bad or useless pattern, however. I've found it useful (if complicated) in Protocol Buffers - which would be much worse off without it. For example:
Foo foo = new Foo.Builder { Name="Jon" }.Build();
wouldn't work if Foo.Build() wasn't strongly typed to return Foo, even though the Build method is specified in IBuilder<...>.
It's worth avoiding this if you easily can simply because it gets so complicated - but I do think it's a useful pattern to know.
You'll normally just want to refer to the base class in that case:
public class Adapter<T> {
public virtual Adapter<T> DoSomething();
Trying to do what you're accomplishing violates the Liskov substitution principal.
If an inherited method in your derived class needs to return the derived type instead of the base type (known as a covariant return type), this is already supported in C#.
I too am having trouble finding an arguable use case for this (though it is an interesting idea).
Are you trying to shift around how you constrain what generic types you can use? It sounds like you want to assume some base functionality without knowing the actual type; that is what Interfaces are for. The where clause is pretty handy for those kinds of problems.
class Dictionary<K, V>
where K : IComparable, IEnumerable
where V : IMyInterface
{
public void Add(K key, V val)
{
}
}
The above example constrains K (the key) so that it must be comparable and enumerable, and V must implement whatever customer functionality you want via your own interface.

Non Generic Versions of Generic classes and interfaces

I often find myself in a situation where I create a generic interface or class and then want to use different versions of this class or interface in a non generic way. For example I may have an interface like this:
interface ICanCreate<T>
{
T NewObject();
}
Which allows a class to be a factory for that type. I then want to register these with a general factory class, so I try to write something like this:
public class Factory
{
private Dictionary<Type, ICanCreate> mappings; // what do I put here????
public void RegisterCreator<T>(ICanCreate<T> creator)
{
}
public T Create<T>()
{
}
}
In the dictionary which type do I use for my value? I don't know if I am missing some sort of design principle and I am aware that this has a lot to do with co(ntra?)variance. Any help or ideas would be much appreciated.
You either have to just use object in your dictionary declaration (it's all private, and you can verify that you'll never put the wrong kind of thing in there) or declare a non-generic ICanCreate interface which ICanCreate<T> extends.
Basically you want a type relationship which can't be expressed in C# - and whenever that happens, you end up with a slightly unpleasant solution, but it looks like you can isolate the ugliness here (i.e. keep it within the single class).
Interestingly, this is a problem that is solved in C# 4.0:
public interface ICanCreate<out T> // covariant
{
T NewObject();
}
public class Factory
{
private Dictionary<Type, ICanCreate<object>> mappings = new Dictionary<Type, ICanCreate<object>>();
public void RegisterCreator<T>(ICanCreate<T> creator) where T:class
{
mappings[typeof(T)] = creator;
}
public T Create<T>()
{
ICanCreate<object> creator = mappings[typeof(T)];
return (T) creator.NewObject(); // I do not think you can get rid of this cast
}
}

Categories