Casting with generics - c#

I'm running into an issue when trying to access an interface property on an implementing class. The problem is, I only have the specific (Cat) type at runtime, so my app breaks when it tries to cast.
Here's what I have:
public class Animal {}
public class Cat : Animal {}
public interface IPetSitter {}
public interface IPetSitter<T> IPetSitter where T : Animal {
T Pet { get; set; }
}
public class Kid { }
public class NeighborhoodKid : Kid, IPetSitter<Animal> {
Animal Pet { get; set; }
}
// --- Implementation ---
// Kid Timmy is instantiated elsewhere
// Animal type "A" is passed in dynamically
if (Timmy is IPetSitter) {
((IPetSitter<A>)Timmy).Pet = new A();
}
This cast will error if the types don't match. I'd love to do something like this:
public interface IPetSitter {
object Pet { get; set; }
}
public interface IPetSitter<T> : IPetSitter where T : Animal {
new T Pet { get; set; }
}
// --- Implementation ---
NeighborhoodKid Timmy = new NeighborhoodKid();
((IPetSitter)Timmy).Pet = new Cat();
But that forces anything implementing IPetSitter to have both [object Pet] and [Cat Pet] properties.
I'd appreciate any ideas. Thanks.
UPDATE: I should have made it more clear initially, but sometimes I will create a Kid class and sometimes a NeighborhoodKid class. That's why I need to cast to IPetSitter<T>. Not all kids I create will be sitting pets. This is starting to sound creepy.

The problem is that you defined
public class NeighborhoodKid : IPetSitter<Animal>
{
Animal IPetSitter<Animal>.Pet { get; set; }
}
and not
public class NeighborhoodKid : IPetSitter<Cat>
{
Cat IPetSitter<Animal>.Pet { get; set; }
}
or
public class NeighborhoodKid<T> : IPetSitter<T> where T : Animal
{
Cat IPetSitter<T>.Pet { get; set; }
}

Timmy, ultimately, was initialized as a NeighborhoodKid. Which means that Pet, for him, as Animal. Timmy is an IPetSitter<Animal>, and you can't cast it to IPetSitter<Cat>.
You could do it the other way around, though, assuming Cat : Animal.
This:
((IPetSitter<Animal>)Timmy).Pet = new Cat();
Actually works simply because Timmy really is IPetSitter<Animal>, since NeighborhoodKid : IPetSitter<Animal>, so you aren't really doing anything with that cast - just accessing the pet property.
The problem with the line after that, isn't accessing to Pet, nor putting Cat into it - it is casting Timmy to IPetSitter<Cat> that is the problem. You are downcasting it to something that it isn't.
You can always up-cast, but you can only down-cast into what you initialized the object with.
If you want NeighborhoodKid to be an IPetSitter of any sort of animal, including animal itself, you should do:
public class NeighborhoodKid<T> : IPetSitter<T> where T : Animal
{
...
}
That way, it is generic, and constraining it to being something that is either an Animal or something that derives from Animal, whether directly or indirectly.
Still, if you initialized it as new NeighborhoodKid<Animal>(), you will not be able to look at it as (aka cast it to) IPetSitter<Cat>, because it was INITIALIZED as an IPetSitter<Animal> (since the generic T parameter given to the NeighborhoodKid constructor was Animal, and is passed to the IPetSitter generic parameter).

Why not just Timmy.Pet = new Cat();?
Just make it public and youll be all set:
public class NeighborhoodKid : Kid, IPetSitter<Animal>
{
public Animal Pet { get; set; }
}
If you create a NeighborhoodKid that doesnt inherit from IPetSitter, the setter wont be availabe.
public class LazyNeighborhoodKid : Kid
{
// Nothing here, hes not a Pet Sitter, can access Pet
}

I'm not really a fan of generics outside of their usefulness in collections, and this is why. You are forcing every NeighborhoodKid to be bound to a single specific type of Animal. What if Timmy can watch cats or dogs? Are you going to create different Timmy instances for each?
Instead, I'm thinking you enforce animal types at at the instance level. For example (I've truncated some of the types for the sake of brevity):
public interface IAnimal {...}
public class Cat : IAnimal {...}
public interface IPetSitter
{
IAnimal Pet { get; set; }
}
public class Kid : IPetSitter
{
public Kid (params Type[] allowedPets) {
_allowedPets = allowedPets;
}
readonly IEnumerable<Type> _allowedPets;
IAnimal _pet;
public IAnimal Pet
{
get {
return _pet;
}
set {
if (!_allowedPets.Contains(value.GetType()) {
throw new InvalidArgumentException("This instance does not support " + value.GetType().Name + ".");
}
_pet = value;
}
}
}
If you leave your enforcement at the instance level, then you don't necessarily need to use concrete casting just to set a property.

Related

How can my base constructor access the derived instance?

I have a base class Animal and a derived class Lion. Each animal should hold a reference to the King of the Jungle, which is always a lion. So a read-only property Lion : KingOfTheJungle is added in the base class. This property is initialized in the Animal's constructor.
The idea is to create first the Lion object, and then pass a reference of it to the constructors of all other animals. The Jungle has only one lion, so when the lion is constructed should recognize itself as the King of the Jungle. The problem is that I can't create the Lion, because I get a compile time error when I pass this as a parameter to base():
abstract class Animal
{
public Lion KingOfTheJungle { get; }
public Animal(Lion theKing)
{
KingOfTheJungle = theKing;
}
}
class Lion : Animal
{
public Lion() : base(this) // Error CS0027
{
}
}
The error I get is:
Error CS0027 Keyword 'this' is not available in the current context
Searching for a workaround I ended up passing null instead of this in the Lion's constructor, and interpeting the null as this in the Animal's constructor:
abstract class Animal
{
public Lion KingOfTheJungle { get; }
public Animal(Lion theKing)
{
KingOfTheJungle = theKing ?? (Lion)this; // OK, but unsafe
}
}
class Lion : Animal
{
public Lion() : base(null) // OK, but not expressive
{
}
}
I don't like this workaround though, because it is neither expressive nor type-safe. Is there any safer or at least more elegant way to do the same thing?
Note: I want to keep the property KingOfTheJungle read-only, without a protected setter. The animals shouldn't be able to change this property after initialization.
I'd suggest KingOfTheJungle could be a virtual (or abstract) readonly property in the base class. Then override it in the inheriting classes.
Something along the lines of:
abstract class Animal
{
public abstract Lion KingOfTheJungle { get; }
}
class Lion : Animal
{
public override Lion KingOfTheJungle
{
get
{
return this;
}
}
}
The correct way to do this is with a static property:
public static Lion KingOfTheJungle { get; } = new Lion();
This solves several problems:
Non-deterministic crowning of the king. With this approach, there is always a king.
Too many kings. With this approach, there is always exactly one Lion that is king. Any other Lion instances are just plain Lion.
Different Animal instances consider different Lion instances their king, depending on which Lion was instantiated at what time.
Many copies of the same reference.
Can't pass this to base constructor. No need now.
If you really want to pursue your original design, IMHO it's worth keeping in mind that the constructor already has the this reference. Remember, this is the same object, no matter which class in the inheritance hierarchy the code exists.
That means a "better" way to do it but still following your original idea would look like this:
abstract class Animal
{
public Lion KingOfTheJungle { get; }
public Animal()
{
KingOfTheJungle = (this as Lion) ?? KingOfTheJungle;
}
}
This still has all but the last problem I mention above though. I would not implement it this way.
You mention that the jungle only ever has one Lion. This further suggests that you should make the Lion class a singleton. That would look something like this:
abstract class Animal
{
public static Lion KingOfTheJungle { get; } = Lion.Instance
public Animal()
{
// ...
}
}
class Lion : Animal
{
public static Lion Instance { get; } = new Lion();
private Lion() { }
}

Issues with C# Covariance in .NET when create a nested, JSON serializable object structure using Dictionaries & Generics

I am experiencing some issues in creating a nested object structure in C# using Dictionaries & Generics (I am using Visual Studio, .NET Framework 4.6+)
The main problem is the absence of covariance in C# Dictionaries.
I have to create this simple (JSON serializable/deserializable) object structure in C#. I try to explain using the animals...
public class AnimalCatalog
{
public Dictionary<string, Animal> AnimalsDict { get; set; } // key is the species name
}
public class Animal // base class
{
public string Species { get; set; } // univocal
public bool CanFly { get; set; }
public Dictionary<string, GenericPaw> PawsDict { get; set; } // each animal has a different type and a different number of paws
}
public class GenericPaw // base class
{
public int FingerNumber { get; set; } // number of finger in each paw
}
public class Cat : Animal // derived class
{
public void meow() // only cats says 'meow'
{...}
}
public class CatPaw : GenericPaw // derived class
{
public void scratch() // cats paws could scratch something :) but not all the animals paws could
{...}
}
I implemented this structure using C# generics, because a Cat has a dictionary of CatPaws, not generic Paws :P. this is my proposal.
public class AnimalCatalog<T,V> where T : Animal<V> where V : GenericPaw
{
public Dictionary<string, T> AnimalsDict { get; set; } = new Dictionary<string, T>(); // key is the species name
}
public class Animal<T> where T : GenericPaw // base class
{
public string Species { get; set; } // univocal
public bool CanFly { get; set; }
public Dictionary<string, T> PawsDict { get; set; } // each animal has a different type and a different number of paws
}
public class GenericPaw // base class
{
public string PawName { get; set; } // univocal
public int FingerNumber { get; set; } // number of finger in each paw
}
public class Cat<T> : Animal<T> where T : CatPaw // derived class
{
public void meow() // only cats says 'meow'
{...}
}
public class CatPaw : GenericPaw // derived class
{
public void scratch() // cats paws could scratch something :) but not all the animals paws could
{...}
}
let's use the created class
Cat<CatPaw> Kitty = new Cat<CatPaw>(); // create a cat
CatPaw KittyFirstPaw = new CatPaw(); // create the 1st cat's paw
Kitty.PawsDict.Add(KittyFirstPaw.PawName, KittyFirstPaw); // add the paw to the dict
AnimalCatalog<Animal<GenericPaw>,GenericPaw> ZooCatalog = new AnimalCatalog<Animal<GenericPaw>,GenericPaw>(); // create a catalog of animals
Animal<GenericPaw> GenericAnimal = Kitty; <-- doens't compile (can't convert derived to base class)
AnimalCatalog.AnimalsDict.Add(GenericAnimal.Species, GenericAnimal);
I also tried using an interface instead of a base class, using the out keyword to specify T as a covariant type, but it doesn't work because I can't use a covariant type in a dict...
Any help is very appreciated :)
Stefano
You can't convert Cat<CatPaw> to Animal<GenericPow>, because then you could add a different kind of GenericPaw into its dictionary (for example a DogPaw) and the cat wouldn't appreciate that.
This is only a problem because you can insert new values in the dictionary, so it seems like it could be solved by using an IReadOnlyDictionary, but unfortunately that one isn't covariant either because of technical issues as described in this question.
On a side note, is there a reason why Cat is also generic?
public class Cat<T> : Animal<T> where T : CatPaw
That would be useful if you want to create a cat that can only have certain specific paws derived from CatPaw. If not, this could become:
public class Cat : Animal<CatPaw>
The AnimalCatalog also seems like it's unnecessarily complex. If you only ever need an animal catalog of Animal, it could be simplified to just one generic parameter:
public class AnimalCatalog<TPaw> where TPaw : GenericPaw
{
public Dictionary<string, Animal<TPaw>> AnimalsDict { get; set; }
}
and if you only ever need an AnimalCatalog<GenericPaw>, you could get rid of the one parameter too. But it's still the case that this catalog would not be very useful since you can't convert an Animal<CatPaw> to Animal<GenericPaw>.
To solve this, you could create a convariant interface of IAnimal<out TPaw> that has all the properties of an Animal but instead of the dictionary, you could either expose paws as an IEnumerable<TPaw> Paws and if you need the dictionary lookup, a method: TPaw GetPaw(string pawName). These would be implemented using the dictionary. Then it's possible to convert a Cat ( which is an Animal<CatPaw> and therefore also IAnimal<CatPaw>) to IAnimal<GenericPaw>. Your animal catalog will then contain IAnimal<GenericPaw>.
Only Interfaces and Delegates allow Covariance. See Microsoft Docs.

Implicit conversations from child(derived) class to parent(base) class

suppose I have two following classes
public class Animal
{
public string name { get; set; }
}
public class Cat: Animal
{
public int age { get; set; }
public string type { get; set; }
}
and now I want to convert my derived class "Cat" match property(e.g. Name) to my base class "Animal" with implicit conversion as following way.
Cat cat = new Cat();
cat.name = "diana";
cat.age = 2;
cat.type = "Siamese-American Shorthair";
Animal animal = new Animal();
animal = (Animal)cat;
// or
animal = cat as Animal;
so while doing above coding it will work fine and will get name property implicit in Animal class object but if I check object of Animal class that is animal actually contains the object of Cat class that is cat and not actually get the object of Animal class.
So please help me to come over this situation so I can directly implicit convert my child class property to my matched class property with proper parent class object.
A cat will always be a cat, even if you are only looking at animals. You cannot remove the actual type of an object; casting it to a parent type will only affect the variable you store it to but the underlying object remains the same.
Cat cat = new Cat(); // cat is a cat
Animal catAnimal = cat; // a cat is also an animal
Console.WriteLine(catAnimal.GetType()); // still a cat
Cat newCat = (Cat)catAnimal;
Console.WriteLine(newCat == cat); // the same cat
Console.WriteLine(animal == cat); // the same cat
First, this is not an implicit conversion, but an explicit one.
An implicit conversion example is this:
int x = 123;
string y = "asdf" + x; // this is the implicit conversion.
Second, you can't "uncat" the cat. it will still be a cat even if your reference is of type object,
Third, any object from any class will keep the properties and fields of it's parent class, unless they are declared as private, so casting a cat to an animal to get it's name property is redundant.
So, can such a cast be useful?
The answer is yes, it might, in the following situations:
Your derived class hides base class functionality using the new keyword.
Your derived class explicitly implements an interface, and the implicit implementation is different then the explicit one.
Here are examples of these situations:
Casting an object to it's base class to use a property or method is when the property or method in the derived class is declared as new:
public class Base {
internal virtual string X() {
return "Base";
}
}
public class Derived1 : Base
{
internal new string X()
{
return "Derived 1";
}
}
public class Derived2 : Base
{
internal override string X()
{
return "Derived 2";
}
}
Derived1 a = new Derived1();
Base b = new Derived1();
Base c = new Derived2();
Console.WriteLine("Derived1 as Derived1: "+ a.X()); // Derived1 as Derived1: Derived 1
Console.WriteLine("Derived1 as Base: " + b.X()); // Derived1 as Base: Base
Console.WriteLine("Derived2 as Base: " + c.X()); // Derived2 as Base: Derived 2
See fiddle here
Casting an object to one of the interfaces it implements, when the class overloads the explicit implementation with an implicit one.
public interface IBlabla {
string bla();
}
public class BlaBla : IBlabla
{
public string bla() {
return "implicit";
}
string IBlabla.bla()
{
return "EXPLICIT";
}
}
BlaBla Myclass = new BlaBla();
Console.WriteLine(Myclass.bla()); // implicit
Console.WriteLine(((IBlabla)Myclass).bla()); // EXPLICIT
See fiddle here
You cannot change an objects type. As Yuval Itzchakov already mentioned you need to create an instance of type Animal. You may only create some kind of copy-constructor for your Animal-class that copied all properties and variables from the given Animal to the new one:
public Animal(Animal animal) {
this.Name = animal.Name;
// further variables and properties to reset the state exactly to the state of the given animal
}
Now you can create an instance of type Animal from every derived type like so:
Animal ani = new Animal(cat);
However that still sounds like a design-flaw (propbably an XY-problem) to me. If you need to access the Name-property of your cat you won´t need to cast to its base-type.
If you really wanted to, you could do something along the lines of
internal class Program
{
public class Animal
{
public string Name { get; set; }
}
public class Cat : Animal
{
public int Age { get; set; }
public string Type { get; set; }
}
public static void Main()
{
var cat = new Cat();
cat.Name = "Puss";
var animal = cat.ToBaseClass<Animal, Cat>();
Debug.Assert(!(animal is Cat));
Debug.Assert(animal.Name == "Puss");
}
}
public static class ReflectionHelper
{
public static TBase ToBaseClass<TBase, TDerived>(this TDerived from)
where TBase : new()
where TDerived : TBase
{
var result = new TBase();
foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(result))
{
propertyDescriptor.SetValue(result, propertyDescriptor.GetValue(from));
}
return result;
}
}
... but it would be pretty ugly ;)
Thanks to all of you who help me to solve my problem and I take everyone answers and comments very seriously.
I have also find another solutions which may be useful to someone. As this questions is regarding conversion with same property from child to parents class, we can use AutoMapper which can do conversion for any class from child to parent class or parent to child class. For that first you can download or update AutoMapper from nuget at give link and add as reference in your project or application.
https://www.nuget.org/packages/AutoMapper/
Now as per my question if I want to convert property from child to parent class than coding using AutoMapper functionality would be as below.
Mapper.CreateMap<Cat, Animal>();
Animal animal = Mapper.Map<Animal>(cat);
I hope this solutions will work for you as it has solved my issues.

Why does a generic type constraint result in a no implicit reference conversion error?

I have created a couple of interfaces and generic classes for working with agenda appointments:
interface IAppointment<T> where T : IAppointmentProperties
{
T Properties { get; set; }
}
interface IAppointmentEntry<T> where T : IAppointment<IAppointmentProperties>
{
DateTime Date { get; set; }
T Appointment { get; set; }
}
interface IAppointmentProperties
{
string Description { get; set; }
}
class Appointment<T> : IAppointment<T> where T : IAppointmentProperties
{
public T Properties { get; set; }
}
class AppointmentEntry<T> : IAppointmentEntry<T> where T : IAppointment<IAppointmentProperties>
{
public DateTime Date { get; set; }
public T Appointment { get; set; }
}
class AppointmentProperties : IAppointmentProperties
{
public string Description { get; set; }
}
I'm trying to use some constraints on the type parameters to ensure that only valid types can be specified. However, when specifying a constraint defining that T must implement IAppointment<IAppointmentProperties>, the compiler gives an error when using a class that is Appointment<AppointmentProperties>:
class MyAppointment : Appointment<MyAppointmentProperties>
{
}
// This goes wrong:
class MyAppointmentEntry : AppointmentEntry<MyAppointment>
{
}
class MyAppointmentProperties : AppointmentProperties
{
public string ExtraInformation { get; set; }
}
The error is:
The type 'Example.MyAppointment' cannot be used as type parameter 'T' in the generic type or method 'Example.AppointmentEntry<T>'. There is no implicit reference conversion from 'Example.MyAppointment' to 'Example.IAppointment<Example.IAppointmentProperties>'.
Could anybody explain why this does not work?
Let's simplify:
interface IAnimal { ... }
interface ICage<T> where T : IAnimal { void Enclose(T animal); }
class Tiger : IAnimal { ... }
class Fish : IAnimal { ... }
class Cage<T> : ICage<T> where T : IAnimal { ... }
ICage<IAnimal> cage = new Cage<Tiger>();
Your question is: why is the last line illegal?
Now that I have rewritten the code to simplify it, it should be clear. An ICage<IAnimal> is a cage into which you can place any animal, but a Cage<Tiger> can only hold tigers, so this must be illegal.
If it were not illegal then you could do this:
cage.Enclose(new Fish());
And hey, you just put a fish into a tiger cage.
The type system does not permit that conversion because doing so would violate the rule that the capabilities of the source type must not be less than the capabilities of the target type. (This is a form of the famous "Liskov substitution principle".)
More specifically, I would say that you are abusing generics. The fact that you've made type relationships that are too complicated for you to analyze yourself is evidence that you ought to simplify the whole thing; if you're not keeping all the type relationships straight and you wrote the thing then your users surely will not be able to keep it straight either.
There is already a very good answer from Eric. Just wanted to take this chance to talk about the Invariance, Covariance, and Contravariance here.
For definitions please see https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance
Let's say there is a zoo.
abstract class Animal{}
abstract class Bird : Animal{}
abstract class Fish : Animal{}
class Dove : Bird{}
class Shark : Fish{}
The zoo is relocating, so its animals need to be moved from the old zoo to the new one.
Invariance
Before we move them, we need to put the animals into different containers. The containers all do the same operations: put an animal in it or get an animal out from it.
interface IContainer<T> where T : Animal
{
void Put(T t);
T Get(int id);
}
Obviously, for fish we need a tank:
class FishTank<T> : IContainer<T> where T : Fish
{
public void Put(T t){}
public T Get(int id){return default(T);}
}
So the fish can be put in and get out from the tank(hopefully still alive):
IContainer<Fish> fishTank = new FishTank<Fish>(); //Invariance, the two types have to be the same
fishTank.Put(new Shark());
var fish = fishTank.Get(8);
Suppose we are allowed to change it to IContainer<Animal>, then you can accidentally put a dove in the tank, in which case tragedy will occur.
IContainer<Animal> fishTank = new FishTank<Fish>(); //Wrong, some animal can be killed
fishTank.Put(new Shark());
fishTank.Put(new Dove()); //Dove will be killed
Contravariance
To improve efficiency, the zoo management team decides to separate the load and unload process (management always does this). So we have two separate operations, one for load only, the other unload.
interface ILoad<in T> where T : Animal
{
void Put(T t);
}
Then we have a birdcage:
class BirdCage<T> : ILoad<T> where T : Bird
{
public void Put(T t)
{
}
}
ILoad<Bird> normalCage = new BirdCage<Bird>();
normalCage.Put(new Dove()); //accepts any type of birds
ILoad<Dove> doveCage = new BirdCage<Bird>();//Contravariance, Bird is less specific then Dove
doveCage.Put(new Dove()); //only accepts doves
Covariance
In the new zoo, we have a team for unloading animals.
interface IUnload<out T> where T : Animal
{
IEnumerable<T> GetAll();
}
class UnloadTeam<T> : IUnload<T> where T : Animal
{
public IEnumerable<T> GetAll()
{
return Enumerable.Empty<T>();
}
}
IUnload<Animal> unloadTeam = new UnloadTeam<Bird>();//Covariance, since Bird is more specific then Animal
var animals = unloadTeam.GetAll();
From the team's point of view, it does not matter what it is inside, they just unload the animals from the containers.
Because you declared your MyAppointment class using the concrete type rather than the interface. You should declare as follows:
class MyAppointment : Appointment<IAppointmentProperties> {
}
Now the conversion can occur implicitly.
By declaring AppointmentEntry<T> with the constraint where T: IAppointment<IAppointmentProperties> you are creating a contract whereby the unspecified type for AppointmentEntry<T> must accommodate any type that is declared with IAppointmentProperties. By declaring the type with the concrete class you have violated that contract (it implements a type of IAppointmentProperties but not any type).
It will work if you re-define the sample interface from:
interface ICage<T>
to
interface ICage<out T>
(please notice the out keyword)
then the following statement is correct:
ICage<IAnimal> cage = new Cage<Tiger>();
In case someone else also has this error message: I found the same interface defined twice in different namespaces and the classes that have been tryed to be linked together did not use the same interface.

Can I implement an interface that contains a property that is of child type to what is required by the interface?

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.

Categories

Resources