c# Upcast with generics - c#

I have defined an abstract class with an abstract constraint :
abstract class Asset<P> where P : Parm { }
abstract class Parm { }
class StockParm : Parm { }
class Stock : Asset<StockParm> { }
class BondParm : Parm { }
class Bond : Asset<BondParm> { }
List<Asset<Parm>> assets = new List<Asset<Parm>>();
Stock stock;
assets.Add(stock);
But I have received the error message:
"Cannot convert type Stock to Asset"
Is there a way to list all the assets?
Thanks

You need to explain to the compiler that Asset<Derived> is Asset<Base>. The compiler compiles generic classes into deperate classes - one for each T. The name of telling the compiler that it is "ok" is covariant.
MSDN:
Covariance - Enables you to use a more derived type than originally specified.
You can assign an instance of IEnumerable (IEnumerable(Of Derived) in Visual Basic) to a variable of type IEnumerable.
Change Asset<T> to an interface and add the out keyword:
interface Asset<out P> where P : Parm { }
public static class Program
{
public static void Main(string[] args)
{
List<Asset<Parm>> assets = new List<Asset<Parm>>();
Stock stock = new Stock();
assets.Add(stock);
}
}
public abstract class Parm { }
public class StockParm : Parm { }
public interface Asset<out P> where P : Parm { }
public class Stock : Asset<StockParm> { }

Please try the following
List<Asset<StockParm>> assets = new List<Asset<StockParm>>();

Related

There is no implicit reference conversion

I have the following code which doesn't compile. I can't figure out why. Can someone please help?
var mercedes = new Mercedes().WithEngine(new LargeEngine());
var volkswagen = new Volkswagen().WithEngine(new SmallEngine());
public class Mercedes : Car<LargeEngine>
{
}
public class Volkswagen: Car<SmallEngine>
{
}
public class Engine
{
}
public class LargeEngine : Engine
{
}
public class SmallEngine : Engine
{
}
public class Car<T> where T : Engine
{
internal T? Engine { get; set; }
}
public static class ExtensionMethods
{
public static TCar WithEngine<TCar>(this TCar car, Engine engine)
where TCar : Car<Engine>
{
car.Engine = engine;
return car;
}
}
The code above doesn't compile with the error:
The type 'Mercedes' cannot be used as type parameter 'TCar' in the
generic type or method 'ExtensionMethods.WithConfiguration(TCar,
Engine)'. There is no implicit reference conversion from 'Mercedes' to
'Car<Engine>'
What I understand is that 'Mercedes' type cannot be casted implicitly into 'Car<Engine>' type. But I also cannot figure out a way to cast it explicitly.
Thanks!
Modify the definition of the WithEngine extension method to take a generic type parameter that is constrained to the Car class, where T is a type parameter that is derived from the Engine class.
public static class ExtensionMethods
{
public static TCar WithEngine<TCar, TEngine>(this TCar car, TEngine engine)
where TCar : Car<TEngine>
where TEngine : Engine
{
car.Engine = engine;
return car;
}
}
Why?
Car<LargeEngine> does not inherit from Car<Engine>, and cannot be implicitly converted to it.
Imagine if generic types did implement inheritance like this. Then we would be able to write the following code:
Mercedes mercedes = new Mercedes();
Car<Engine> car = mercedes;
// Clearly *this* should not be allowed
car.Engine = new SmallEngine();

Assign a sub class to an interface, with generics and covariant involved

I defined 3 interfaces:
public interface IManufacturerInput
{
}
public interface IManufacturerOutput
{
}
public interface IManufacturerApi<in S, out T>
where S : IManufacturerInput
where T : IManufacturerOutput
{
T Calculate(S);
}
And I defined a specific Manufacturer:
public class ManufacturerAInput : IManufacturerInput
{
}
public class ManufacturerAOutput : IManufacturerOutput
{
}
public class ManufacturerAApi : IManufacturerApi<ManufacturerAInput, ManufacturerAOutput>
{
public ManufacturerAOutput Calculate(ManufacturerAInput)
{
return null;
}
}
And In Main() I created a ManufacturerAApi, and try assign it to IManufacturerApi.
IManufacturerApi<IManufacturerInput, IManufacturerOutput> api = new ManufacturerAApi();
But it failed. The error message said (just abstract meaning):
Can't convert from ManufacturerAApi to IManufacturerApi<IManufacturerInput, IManufacturerOutput>
So is there any way I can make the assignment work? Thanks in advance.
What you are proposing isn't type safe. Let's change the names of your types to make the issue clearer:
public interface IPetFood { }
public interface IPetSound { }
public interface IPetCage<in S, out T>
where S : IPetFood
where T : IPetSound
{
T Feed(S s);
}
public class DogFood : IPetFood { }
public class CatFood : IPetFood { }
public class Bark : IPetSound { }
public class DogCage : IPetCage<DogFood, Bark>
{
public Bark Feed(DogFood input)
{
return new Bark();
}
}
And now suppose this is legal:
IPetCage<IPetFood, IPetSound> api = new DogCage();
Then we could do the following:
api.Feed(new CatFood()); //oops we've just given the dog some catfood.
The assignment will not work because S is contravariant, which means that any possible IPetFood passed into api.Feed would need to be a subtype of DogFood and you have the opposite; IPetFood is a superset of DogFood.

Enforcing generic interface childs type

I have a generic interface (MyInterface<T>), which is implemented by the class ChildA in the example below:
public interface MyInterface<T>
{
MyObj<T> GetObj(); // Irrelevant
}
class ChildA : MyInterface<ChildA>
{
// Irrelevant:
MyObj<ChildA> GetObj() {
return new MyObj<ChildA>();
}
}
This works, but I need to make sure that <T> always has the type of the implementing class, so in this case T should always be of type ChildA, because it is implemented by ChildA.
Another correct implementation could be this, for example:
class ChildB : MyInterface<ChildB> { ... }
But currently, this incorrect implementation is also possible, while it should not be:
class ChildA : MyInterface<ChildB> { ... }
Is there a way to enforce this?
You cannot enforce a generic type argument to be constrained to the implementing type.
The available type constraints are the following:
where T : struct
where T : class
where T : new()
where T : <base class name>
where T : <interface name>
where T : U
There is nothing like where T : self in C#. Actually, it wouldn't even make sense, because such a thing cannot be meaningfully enforced. Besides, it wouldn't fit at all into the covariance/contravariance concepts and would be weird to inherit from, in general.
The closest thing you can do is this:
public interface IMyInterface<T> where T : IMyInterface<T>
{
MyObj<T> GetObj();
}
Why it wouldn't make sense
Let's say you could do this:
public interface IMyInterface<T> where T : self // this syntax does not exist in C#
{
MyObj<T> GetObj();
}
Now all implementing types would have to use themselves as the type argument. But you could still do this:
public class ChildC<T> : IMyInterface<T> where T : self
{
/* ... */
}
Which would go around your restriction.
Is there a way to enforce this?
Well, not with generic constraints. You can do that with reflection though i'd vote against it :
public abstract class BaseChild<T> : MyInterface<T>
{
protected BaseChild()
{
if (typeof(T) != this.GetType())
{
throw new InvalidOperationException(string.Format(
"Type {0} is not supported as valid type parameter for type {1}",
typeof(T).Name, this.GetType().Name));
}
}
}
Example :
class ChildA : BaseChild<int> { }
// Bang! throws
var instance = new ChildA();
.
class ChildB : BaseChild<ChildB> { }
// Ok here
var instance = new ChildB();
You cannot do this but you can create your own control comparing the generic type of the interface and the type of your class. See the example:
class ChildA : MyInterface<ChildB>
{
public ChildA()
{
this.ValidateGenericType();
}
public MyObj<ChildB> GetObj()
{
return new MyObj<ChildB>();
}
protected void ValidateGenericType()
{
//throws an Exception because ChildB is different of ChilA
if (this.GetType().Name != this.GetType().GetInterfaces()[0].GetGenericArguments()[0].Name)
{
throw new Exception("The generic type must be of type ChildA.");
}
}
}
It seems that you should use extension methods instead of enforcing some interface for this purpose
public interface ISomeInterface {}
public class Child: ISomeInterface {}
public class OtherChild : ISomeInterface { }
public static class MyInterfaceExtensions
{
public static MyObj<T> GetMyObj<T>(this T child) where T : ISomeInterface
{
return new MyObj<T>();
}
}
public static class Test
{
public static void RunTest()
{
var child = new Child();
var otherChild = new OtherChild();
MyObj<Child> myObj = child.GetMyObj();
MyObj<OtherChild> myOtherObj = otherChild.GetMyObj();
}
}

Protected generic class - is it supported?

I had a question on C# generics. I wish to store a generic type variable in my abstract class without declaring that type outside the class.
Below is the code sample. Please note that I do not wish to make the Param classes exposed outside the Calc class.
Thanks in advance.
- Dutta.
abstract class Base { }
abstract class Calc<T> where T : Base
{
protected Param Member; /* how can this be a made a generic declaration
* WITHOUT declaring this class like,
* class Calc<T, P>
* where T : Base
* where P : Param */
protected Calc(Param p)
{
this.Member = p;
}
protected abstract class Param { }
}
class MyBase : Base { }
class MyCalc : Calc<MyBase>
{
public MyCalc() : base(new MyParam()) { }
public void doSomething()
{
base.Member.A++; // fails on compilation
}
private class MyParam : Calc<MyBase>.Param
{
public int A;
public MyParam() { this.A = 0; }
}
}
You just need to cast it to the new type, because no matter what, the variable Member was declared as Param and it will always be accessed as Param:
((MyParam)base.Member).A++;
Secondly, you can fix up your MyParam class by changing from this:
MyParam : Calc<MyBase>.Param
To this:
MyParam : Param
Because Param is already Calc<MyBase> through generics and inheritance.
Thraka's answer is correct: if you don't want to use generics you need to cast. Just to add to it, in case what you're really trying to do looks something like this. Here's a set of classes that you can expose from your library, which will not be extensible by clients (unless they're running with full trust and can use reflection etc.!!) but which can be used in a type-safe way.
public abstract class SupportedPaymentMethod
{
protected internal SupportedPaymentMethod() { }
}
public sealed class Check : SupportedPaymentMethod
{
public int CheckNumber { get; private set; }
public Check(int checkNumber)
: base()
{
CheckNumber = checkNumber;
}
}
public sealed class CreditCard : SupportedPaymentMethod
{
public CreditCard()
: base()
{ }
}
public abstract class Payment<T>
where T : SupportedPaymentMethod
{
public T Method { get; private set; }
protected internal Payment(T method)
{
Method = method;
}
}
public sealed CheckPayment : Payment<Check>
{
public CheckPayment(Check check)
: base(check)
{ }
}
public sealed CreditCardPayment : Payment<CreditCard>
{
public CreditCardPayment(CreditCard creditCard)
: base(creditCard)
{ }
}
Clients (i.e. code outside of your class library's assembly) will be able to instantiate a CheckPayment or a CreditCardPayment, but they will not be able to create a new class deriving from Payment<T>. So, it will not be possible for clients to create a CheatingPaymentMethod : Payment<Cheating>, for example. :)
Calls like your intended call to base.Member.A++ will now work:
var checkPayment = new CheckPayment(new Check(123456));
var checkNumber = checkPayment.Method.CheckNumber; // Success! :)

Covariance issue

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

Categories

Resources