Reputation: 597
The following code is a simple example of a program I am writing.
public class Y
{ }
public class X : Y
{ }
public class W : Y
{ }
public interface IAaa<T>
where T : Y
{
void Execute(T ppp);
}
public abstract class Aaa<T> : IAaa<T>
where T : Y
{
public abstract void Execute(T ppp);
}
public class Bbb : Aaa<X>
{
public override void Execute(X ppp)
{ }
}
public class Ccc : Aaa<W>
{
public override void Execute(W ppp)
{ }
}
public class Factory
{
public static IAaa<Y> Get(bool b)
{
if(b)
return new Bbb();
else
return new Ccc();
}
}
class Program
{
static void Main(string[] args)
{
IAaa<Y> aa;
aa = Factory.Get(true);
}
}
when I compile it I get the following errors
error CS0266: Cannot implicitly convert type 'ConsoleApplication3.Bbb' to 'ConsoleApplication3.IAaa'. An explicit conversion exists (are you missing a cast?)
error CS0266: Cannot implicitly convert type 'ConsoleApplication3.Ccc' to 'ConsoleApplication3.IAaa'. An explicit conversion exists (are you missing a cast?)
Is there any way to make it work?
Upvotes: 2
Views: 565
Reputation: 663
You could cast to (IAaa<Y>
) and your code would compile.
However it will not work and will fail at run-time.
Why?
Your classes Bbb
and Ccc
are specialized classes and the Execute method cannot process ALL types of Aaa
. You have to tell C# / the compiler.
UPDATE:
By having a generic Factory you can get specialized instances of IAaa and your code should work.
In your Program
you already know the type as you pass TRUE or FALSE to the Factory, so you need to explicitly tell C# the type of the Interface implementation you want to use.
(refactor the Factory class accordingly, I'm just sending what should compile)
public class Y
{ }
public class X : Y
{ }
public class W : Y
{ }
public interface IAaa<T>
where T : Y
{
void Execute(T ppp);
}
public abstract class Aaa<T> : IAaa<T>
where T : Y
{
public abstract void Execute(T ppp);
}
public class Bbb : Aaa<X>
{
public override void Execute(X ppp)
{ }
}
public class Ccc : Aaa<W>
{
public override void Execute(W ppp)
{ }
}
public class Factory<T> where T : Y
{
public static IAaa<T> Get(bool b)
{
if(b)
return (IAaa<T>)new Bbb();
else
return (IAaa<T>)new Ccc();
}
}
class Program
{
static void Main(string[] args)
{
IAaa<X> aa;
aa = Factory<X>.Get(true);
}
}
UPDATE 2
Just an example of how you could refactor the Factory class:
public class Factory<T, U>
where T : Y
where U : Aaa<T>, new()
{
public static IAaa<T> Get()
{
return (IAaa<T>)new U();
}
}
class Program
{
static void Main(string[] args)
{
IAaa<X> aa;
aa = Factory<X, Bbb>.Get();
}
}
Upvotes: 0
Reputation: 56536
You can't use the interface in the way you're trying to. Lookup covariance/contravariance, you're trying to do the opposite of what's possible (you have in interface that could be <in T>
but you're trying to use it like <out T>
).
Take class Bbb
for instance - it has an Execute(X)
method. What would happen if you tried to pass a Y
(which may or may not be an X
) to that? The compiler doesn't allow it, because you never defined in the code what should happen in that case.
You can do what you want by creating and implementing another interface, IAaa
. E.g.
public interface IAaa
{
void Execute(Y ppp);
}
Perhaps implemented like this, so that if you try to call it with an invalid type, a cast exception is thrown:
void Main()
{
IAaa aa;
aa = Factory.Get(true);
}
public class Y
{ }
public class X : Y
{ }
public class W : Y
{ }
public interface IAaa<T> : IAaa
where T : Y
{
void Execute(T ppp);
}
public interface IAaa
{
void Execute(Y ppp);
}
public abstract class Aaa<T> : IAaa<T>
where T : Y
{
public abstract void Execute(T ppp);
void IAaa.Execute(Y ppp)
{
this.Execute(ppp);
}
protected abstract void Execute(Y ppp);
}
public class Bbb : Aaa<X>
{
public override void Execute(X ppp)
{ }
protected override void Execute(Y ppp)
{
this.Execute((X)ppp);
}
}
public class Ccc : Aaa<W>
{
public override void Execute(W ppp)
{ }
protected override void Execute(Y ppp)
{
this.Execute((W)ppp);
}
}
public class Factory
{
public static IAaa Get(bool b)
{
if(b)
return new Bbb();
else
return new Ccc();
}
}
Upvotes: 1
Reputation: 567
As the error says, you are missing a cast. I believe this is what you need:
public static IAaa<Y> Get(bool b)
{
if(b)
return (IAaa<Y>)(new Bbb());
else
return (IAaa<Y>)(new Ccc());
}
Upvotes: 0