I have the following Classes / Interfaces:
// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }
// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<T> where T : IA { }
I try to create a new instance using the following code:
IB<IA> foo = new B();
I am getting the following error:
Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?)
Can someone please explain why this is not possible?
OK, let's replace A with Fish, IA with IAnimal, B with Aquarium, and IB<T> with IContainer<T>. And we'll add a member to IContainer<T>, and a second implementation of IAnimal:
// Model
public class Fish : IAnimal { }
public class Tiger : IAnimal { }
// ModelLogic
public class Aquarium : IContainer<Fish>
{
public Fish Contents { get; set; }
}
// Model Interface
public interface IAnimal { }
// ModelLogic Interface
public interface IContainer<T> where T : IAnimal
{
T Contents { get; set; }
}
IContainer<IAnimal> foo = new Aquarium(); // Why is this illegal?
foo.Contents = new Tiger(); // Because this is legal!
You can put a Tiger into foo -- foo is typed as a container that can contain any animal. But you can only put a Fish into an Aquarium. Since the operations you can legally perform on an Aquarium are different than the operations you can perform on an IContainer<IAnimal>, the types are not compatible.
The feature you want is called generic interface covariance and it is supported by C# 4, but you have to prove to the compiler that you will never put a tiger into your fish tank. What you want to do is:
// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }
// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<out T> where T : IA { }
Notice the covariance annotation on IB. This out means that T can only be used as an output, not as an input. If T is only an output then there is no way for someone to put a tiger into that fish tank because there is no "put into" property or method possible.
I wrote a number of blog articles while we were adding that feature to C#; if you are interested in the design considerations that went into the feature, see:
http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/
To fix your code, just change
public interface IB<T> where T : IA { }
to
public interface IB<out T> where T : IA { }
It's not easy to see when you have empty interfaces. Consider you have one method M in interface IB:
public interface IB<T> where T : IA
{
void M(T t);
}
And here is implementation of B:
public class B : IB<A>
{
public void M(A t)
{
// only object of type A accepted
}
}
Then you have object C, which also implements IA:
public class C : IA { }
So, if your code would be possible, then you could call:
IB<IA> foo = new B();
foo.M(new C());
Problem is that class B accepts only objects of type A. Error!
Related
I have a set up approximately like this:
public class A { ... }
public class A<T> : A { ... }
public class B<T> : A<T> { ... }
public class C : B<SomeType> { ... }
I am iterating over a list of type A, and I want to check if something is of type B, and if it is, convert it to... B... I can see how it already poses a problem of how am I gonna get the type... but if I cannot do that, what are my other alternatives?
EDIT:
To clarify, B contains a method I'd like to use that A does not contain as it simply has no need for it... I want to check which of the objects on that list are of type B so that I can run this method on them
EDIT 2:
I forgot to mention the A in the middle earlier... sorry for the confusion
I want to check which of the objects on that list are of type B
Then introduce a type B into your type hierarchy. Currently you don't have a type B, you've got B<SomeType> which is a different type. so
public class A { ... }
public abstract class B : A { ... }
public class B<T> : B { ... }
public class C : B<SomeType> { ... }
Or declare the method you want on an interface
public class A { ... }
public class A<T> : A { ... }
public interface IB
public class B<T> : A<T>, IB { ... }
public class C : B<SomeType> { ... }
Then for any A you can check if it is IB. This is probably the most natural solution since .NET doesn't have multiple inheritance.
I have a
public class A<T> where T : IBase
{
//Does something
}
I need a second class that behaves like a collection of class A
public class B<A<T>> : IEnumerable<A<T>> where T : IBase
{
}
The problem is that I do not want to create classes like
public class B<A<MyCustomObjectP>> : IEnumerable<A<MyCustomObjectP>>
{
}
public class C<A<MyCustomObjectQ>> : IEnumerable<A<MyCustomObjectQ>>
{
}
and so on.. I would like to let the CustomObject be a generic type parameter that implements IBase.
I found that even doing this is illegal:
public class B<T, U> : IEnumerable<T> where T : A<U> where U : IBase
{
}
How could I achieve this type of behaviour, if this is illegal? Is there a better design pattern of sorts that might help?
The IBase constraint is defined on A<T>, so it must be defined again on all generic classes, that want to use A<U> (using U to distinguish from T in A<T> class definition, but it can be called anything). You should be able to do simply:
public class B<T> : IEnumerable<A<T>> where T : IBase { ... }
You wrote that you need a second class that behaves like a collection of class A.
Since you have other classes (like B) inheriting from IBase as well, which you want to add, you can make the collection a collection of IBase.
Hence the solution would look like this (note that I have used List but you can easily replace that by IEnumerable - but then you have to implement methods like .Add yourself):
void Main()
{
var items = new CollectionOf<IBase>(); // create list of IBase elements
items.Add(new A() { myProperty = "Hello" }); // create object of A and add it to list
items.Add(new B() { myProperty = "World" }); // create object of B and add it to list
foreach(var item in items)
{
Console.WriteLine(item.myProperty);
}
}
// this is the collection class you asked for
public class CollectionOf<U>: List<U>
where U: IBase
{
// collection class enumerating A
// note you could have used IEnumerable instead of List
}
public class A: IBase
{
// class A that implements IBase
public string myProperty { get; set; }
}
public class B: IBase
{
// class B that implements IBase too
public string myProperty { get; set; }
}
public interface IBase {
// some inteface
string myProperty { get; set; }
}
I'm facing a bit of problem with the following casting:
class A
{
}
class B : A
{
}
class C<T> where T : A
{
protected T property { get; set; }
}
class D : C<B>
{
}
class MainClass
{
public static void Main (string[] args)
{
C<A> x = new D();
// Error CS0029: Cannot implicitly convert type `SampleApp.D' to `SampleApp.C<SampleApp.A>' (CS0029) (SampleApp)
}
}
I don't understand why this is failing since D is wider than C<A> since it implements C<B>, and B : A. Any workarounds?
If you can use C# 4.0, you can write the following code.
class A { }
class B : A {}
interface IC<out T> {}
class C<T> :IC<T> where T : A { protected T property { get; set; } }
class D : C<B> {}
class MainClass {
public static void Main()
{
IC<A> x = new D();
}
}
Let's name your classes Animal for A, Barker for B, and Dog for D.
Actually C<Animal> is wider than Dog : C<Barker>. Assume you have public property Me of type T and assignment possible:
C<Animal> a = new Dog();
a.Me = Elephant; // where Elephant inherited from Animal
Oops! Dog is parametrized with Barker. Have you seen barking elephants?
You need to declare some covariant interface to allow assignment of class instantiated with more derived type argument C<Barker> to object instantiated with less derived type argument C<Animal>. You can use empty interface, like #NickW suggested, but you will not be able to do something with instance of that interface (it's empty!). So, let's do something like that:
interface IC<out T>
where T : Animal
{
IEnumerable<T> Parents(); // IEnumerable is covariant
T Me { get; } // no setter
}
class C<T> : IC<T>
where T: Animal
{
// implementation
}
class D : C<Barker>
{
// implementation
}
Above scenario is still impossible, but now you can
IC<Animal> a = new Dog();
foreach(var parent in a.Parents)
Console.WriteLine(parent);
Console.WriteLine(a.Me);
You can't do that because the Generics are actualy templates and they don't act like what you want to do with them. Let me show you by this:
When you say "C<A>" it means a generic class by a "parameter" of "A".
BUT
When you say "D" it means exactly "D"!
So D is not equal to a generic class by a parameter of A. As you can simply see it in the result of ToString function on both types (by using typeof).
Hope it helps
Cheers
I need to hold a list of object types that are allowed to do certain actions.
Example Animal has 3 descendants Tiger, Human, Hippo
I want to allow only Tigers and Hippos to be held in zoo cages? I need a list of animal types.
I would love something better than List<Type>
This is just a simplified example. I don't like animals in cages..
edit
Since it's not clear. I want to hold object types in the list and not actual objects.
Example:
List<Type> types = new List<Type>();
types.Add(typeof(Hippo));
types.Add(typeof(Tiger));
This has the limit that a programmer can do types.Add(typeof(Human)) and this is what I wan't to dissallow.
edit2
Just to clarify my question. I want to be able to dynamically Register allowed types and not having consequent ifs as some answers bellow.
If you want a list of only certain types:
There isn't anything in generics that can support what you are asking for, so simply create a custom type that allows you to store Type types and have code at runtime for guarding against invalid entries:
public class CagedTypes
{
private readonly List<Type> _types;
public void Add(Type t)
{
if (t == typeof(Hippo) || t == typeof(Tiger))
_types.Add(t);
}
}
Although I can't see why you might need this.
Alternative if you want a list of only certain types:
Do the same as above, but include the interface below and change the add check to something like:
public void Add(Type t)
{
if (t.GetInterfaces().Contains(typeof(ICanBeHeldInZooCage)))
_types.Add(t);
}
You could also use attributes, as you can query a type for any attributes using the GetAttributes method.
If you wish to only have certain instances in a list:
Create a marker interface:
public interface ICanBeHeldInZooCage
That Tiger and Hippo implement (doesn't have to do anything), then you can have:
var cagedAnimals = new List<ICanBeHeldInZooCage>();
Approach1 - via interfaces:
public interface ICageable
{ }
public abstract class Animal
{}
public class Hippo : Animal, ICageable
{}
public class Human : Animal, ICageable
{}
public IEnumerable<Type> GetCageableAnimals()
{
return GetAssemblyTypes(assembly:typeof(Animal).Assembly)
.Where(type=>IsDerivedFrom(type, typeof(Animal)))
.Where(type=>ImplementsInterface(type,typeof(ICageable)));
}
Approach 2 - via attribute:
public class InCageAttribute : Attribute
{ }
public abstract class Animal
{}
[InCage]
public class Hippo : Animal
{}
public class Human : Animal
{}
public IEnumerable<Type> GetCageableAnimals()
{
return GetAssemblyTypes(assembly:typeof(Animal).Assembly)
.Where(type=>IsDerivedFrom(type, typeof(Animal)))
.Where(type=>MarkedByAttribute(type,typeof(InCageAttribute)));
}
UPDATE
IMPORTANT
Both these approaches provide only runtime check. having compilation check implementation would be better, but don't know for know how to achieve that.
UPDATE2
For dynamic registration:
public class CageRegistry
{
private List<Type> _allowedTypes = new List<Type>();
public IEnumerable<Type> AllowedTypes{get{return _allowedTypes;}}
public bool TryAdd(Type type)
{
if(ImplementsInterface(type, typeof(ICageable)))// for approach with attributes code is pretty similar
{
_allowedTypes.Add(type);
return true;
}
return false;
}
}
PS2
Sorry for not implemented methods like MarkedByAttribute, IsDerivedFrom and ImplementsInterface - I just don't have visual studio on current machine yet and don't remember api exactly.
How about an Interface?
public interface ICageable {}
public abstract class Animal {}
public class Hippo : Animal, ICageable {}
public class Tiger : Animal, ICageable {}
public class Human : Animal, ICageable {}
public class Ape : Animal {}
....
List<ICageable> ZooAnimals = new List<ICageable>{hippo, tiger, human};
(writing from a Planet of the Apes perspective)
and if you need the types themselves in a list, well types are instances of the Type type, so whatever you create it will be a collection of types. You could encapsulate is like this:
public class CageableTypesCollection :
{
private List<Type> _cageableTypes;
public CageableTypesCollection()
{
_cageableTypes = new List<Type>();
}
public RegisterType(Type t)
{
if (!typeof(ICageable).IsAssignableFrom(t))
throw new ArgumentException("wrong type of type");
_cageableTypes.Add(t);
}
public UnregisterType(Type t)
{
....
}
.....
}
I would use an interface to determine if an animal is a ZooAnimal
public class Animal
{
public string Name;
}
public class Tiger : Animal, IZooAnimal
{
}
public class Human : Animal
{
}
public interface IZooAnimal
{
//Some zoo animal properties
}
And then check if the animal is a Zoo Animal if (a is IZooAnimal) below is a zoo class which you could use.
public class Zoo
{
public List<IZooAnimal> AnimalsInZoo = new List<IZooAnimal>();
public void AddAnimal(IZooAnimal a)
{
AnimalsInZoo.Add(a);
}
}
EDIT:
Ok now to do this with types and constrain the types to a ZooAnimal I have made a generic zoo class which takes T where T is a ZooAnimal - you could have a list of ZooAnimals or a list of tigers in our case.
public class Zoo<T> where T : IZooAnimal
{
public List<Type> AnimalTypes = new List<Type>();
public void AddType(Type a)
{
if (typeof(T) == a)
AnimalTypes.Add(a);
}
}
This will add type Tiger to the AnimalsInZoo. Hope this works for you.
Zoo<IZooAnimal> cage = new Zoo<IZooAnimal>();
cage.AddType(typeof(Tiger));
cage.AddType(typeof(Human));
Human is animal, Tiger is animal that should be in zoo. So in your case I'd create one more base class for Tiger and Hippo.
public class AnimalInZoo : Animal {}
public class Tiger : AnimalInZoo {}
public class Hippo : AnimalInZoo {}
public class Human : Animal {}
You can create helper function AddInZoo(AnimalInZoo obj) to add in you List<Type> m_Zoo:
void AddInZoo(AnimalInZoo obj)
{
m_Zoo.Add(obj.GetType());
}
The other option:
public abstract class Animal
{
public abstract bool IsCagable { get; }
}
And let the nested classes to implement their behavior.
Later then, the some sort of Zoo class which is mostly presented in the answers in this topic, inside the method Add must do the check:
public sealed class ZooList : List<Animal> // I believe you need Animal, not Type
{
// ... some implementations ...
public override sealed void Add(Animal animal)
{
if (!animal.IsCagable)
// Prevent from adding.
}
}
I am receiving the following error:
ClassName.PropertyName cannot implement IClassType.PropertyName
because it does not have the matching return type of IBasePropertyType
Now, for the code:
public class ClassName : IClassType
{
public IChildPropertyType PropertyName { get; set; }
}
public interface IClassType
{
public IBasePropertyType PropertyName { get; set; }
}
public interface IBasePropertyType
{
// some methods
}
public interface IChildPropertyType : IBasePropertyType
{
// some methods
}
Is there a way to do what I am attempting? I know that the issue is with co/contravariance, but I can't seem to figure out how to do this.
In order to implement the given interface, you must have the same return type. However, there are a couple of potential work-arounds to make life easier:
make your interface generic
implement the interface explicitly.
If you make IClassType generic, like so:
public interface IClassType<T> where T : IBasePropertyType
{
public T PropertyName { get; set; }
}
... then you can implement this interface using various property types:
public class ClassName : IClassType<IChildPropertyType>
{
public IChildPropertyType PropertyName { get; set; }
}
Another option would be to leave your interface non-generic, but to have a generic base type that explicitly implements the interface:
public class ClassBase<T> : IClassType
where T : IChildPropertyType
{
IBasePropertyType IClassType.PropertyName {
get {return PropertyName;}
set {PropertyName = (IChildPropertyType)value;}
}
T PropertyName {get;set;}
}
Note that this last option is not quite ideal because you must dynamically cast the property to the given child type: while you can guarantee that every IChildProperty type is an IBasePropertyType, you cannot guarantee that every IBasePropertyType is an IChildPropertyType. However, if you can eliminate the setter from the original interface, or if you can take other steps to guarantee that the setter will never be called with the wrong type in your code, then this could work.
You are correct that this has to do with covariance; specifically it has to do with virtual method return type covariance, which is not a kind of covariance that the C# language supports.
UPDATE: This answer is over ten years old. C# may soon implement return type covariance. Please see https://github.com/dotnet/csharplang/issues/49 for details.
Note that even if it did, the system you describe is not type safe. Suppose we have:
interface IAnimal {}
interface IGiraffe : IAnimal {}
interface ITiger: IAnimal {}
class Tiger : ITiger {}
interface IHaveAnAnimal { IAnimal Animal { get; set; } }
class C : IHaveAnAnimal
{
public IGiraffe Animal { get; set; }
}
...
IHaveAnAnimal x = new C();
x.Animal = new Tiger(); // Uh oh. We just put a Tiger into a property of type IGiraffe.
Even if the covariance were legal at all, this kind of covariance would not be legal; you'd have to have no setter for the covariance to be legal.
Suppose then you did have no setter:
interface IAnimal {}
interface IGiraffe : IAnimal {}
interface ITiger: IAnimal {}
class Tiger : ITiger {}
interface IHaveAnAnimal { IAnimal Animal { get; } }
class C : IHaveAnAnimal
{
public IGiraffe Animal { get; }
}
Unfortunately this is still not legal. But you can do this:
class C : IHaveAnAnimal
{
IAnimal IHaveAnAnimal.Animal { get { return this.Animal; } }
public IGiraffe Animal { get; }
}
Now when C is used as a C, Animal returns a giraffe, and when used an an IHaveAnAnimal, it returns an IAnimal.