Context: .NET 4.0, C#
I'm creating a set of interfaces and a set of clases that implement them to provide some service. The clients use the concrete clases but call methods that are declared using the interfaces as parameter types.
A simplified example is this one:
namespace TestGenerics
{
// Interface, of fields
interface IField
{
}
// Interface: Forms (contains fields)
interface IForm<T> where T : IField
{
}
// CONCRETE CLASES
class Field : IField
{
}
class Form <T> : IForm<T> where T : IField
{
}
// TEST PROGRAM
class Program
{
// THIS IS THE SIGNATURE OF THE METHOD I WANT TO CALL
// parameters are causing the error.
public static void TestMethod(IForm<IField> form)
{
int i = 1;
i = i * 5;
}
static void Main(string[] args)
{
Form<Field> b = new Form<Field>();
Program.TestMethod(b);
}
}
}
The code makes sense to me, but I get the compiler error:
Argument 1:
cannot convert from 'TestGenerics.Form<TestGenerics.Field>' to
'TestGenerics.IForm<TestGenerics.IField>' TestGenerics
I'm not sure what I'm doing wrong, I've read lots of pages on the internet but none solved my problem.
Is there a solution that would not modify that much the architecture of what I'm trying to build:
Edit:I designed the interfaces in a way such that they should be independent of concrete clases that implement them. The concrete clases could be loaded from a dll, but most of the application Works with the interfaces. In some cases I need to use concrete clases, specially when using clases that need to be serialized.
Thanks in advance.
Alejandro
The problem is that Form<Field> implements IForm<Field> but not IForm<IField>. You cannot use an inherited class (or interface) as a generic parameter unless it is marked as covariant with the out identifier. However, marking your interface as covariant will restrict the usage significantly (basically making in an "output-only" interface like IEnumerable) so it may not work for you.
One way to get it to work is to make TestMethod generic as well:
public static void TestMethod<T>(IForm<T> form) where T:IField
{
int i = 1;
i = i * 5;
}
You can use Covariance, like so:
interface IForm<out T> where T : IField
{
}
More about Covariance and Contravariance here.
Others have pointed out the reasoning behind the error message, but let's examine the design of your sample code for a moment. Perhaps you're using a generic where none is needed.
You've already said you're using methods declared in the IField interface, so there may be no need to make your IForm class generic - simply have it store references to IField, instead of the generic argument 'T' (which is already guaranteed to be an IField anyway).
For instance, use:
public interface IForm
{
IEnumerable<IField> Fields { get; set; }
}
instead of
public interface IForm<T> where T : IField
{
IEnumerable<T> Fields { get; set; }
}
Related
This question already has answers here:
C# - Multiple generic types in one list
(3 answers)
Closed 1 year ago.
I have the following class and interface
abstract class MyAbstractClass<T> where T : MyInterface
{
}
interface MyInterface {
}
I would like to have the following class:
class ContainerClass
{
private List<MyAbstractClass<T>> actions = new List<MyAbstractClass<T>>();
}
Where T is any class that extends MyInterface.
The important bit is here that is do not want to add a generic parameter to the ContainerClass and I need the exact implementation class, not the interface, so I can't just say:
private List<MyAbstractClass<MyInterface>> actions = new List<MyAbstractClass<MyInterface>>();
Long story short, I would like the following Java code in C#:
public class ContainerClass {
private List<MyAbstractClass<? extends MyInterface>> list = new ArrayList<>();
}
abstract class MyAbstractClass<T extends MyInterface> {
}
interface MyInterface {
}
Is possible in C#?
EDIT:
To clarify the question, let's see the below code piece:
abstract class GameAction<T> where T : IGameEntity
{
protected T Subject;
public GameAction(T subject)
{
Subject = subject;
}
public abstract bool Run();
}
class ActionRunner {
private List<GameAction<T>> actions = new List<GameAction<T>>();
public void RunAll() {
foreach (GameAction<T> action in actions) {
action.Run();
}
}
}
My goal here is to have different implementation classes of GameAction, each should be parameterized with different implementations of IGameEntity. IGameEntity can be considered now as marker interface (it has some methods, but they don't matter here), I just use it to enforce the type of Subject and to avoid repeated casting in the implementation classes. The member Subject can be anything, it can do anything in the Run method of the child classes.
What you ask for is not possible in C# because unfortunately only interfaces are allowed to have variant type parameters. As you said, in Java you would be able to declare a covariant variable, but in .net, due to various design decisions, you cant.
The only choice you have is to create a new interface
public interface MyAbstractClassWhenInReadOnlyList<out T>
{
T Method1();
void Method2(out T result);
...
}
and have your MyAbstractClass implement that interface.
There are some other choices, but they boil down to this, just in various guises. There is no way to access or use an object with a type variable without knowing the exact type that was used to construct the object. You must have a class without a type variable to use it (This includes reflection) or have an interface with the appropriate variance.
Please be aware that this has noting to do with Java's wild-card syntax nor the use-site vs declarations site variance syntax. These are both just notations used by the two programming languages to express an idea to the type checker.
Ultimately it comes down to static variables.
If a method accesses the List< int >.count variable vs the List< String > variable then it better be the correct value. In Java, static variables are associated with the "raw class", eg the type "List< ? extends Object >. In C# there are two variables, one associated with each set of type parameters.
Because Interfaces are unable to have static variables, there is no way that a static variable could be access incorrectly.
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.
Let's say I have an interface that many many distinct classes implement:
public interface IHaveObjects
{
object firstObject();
}
(Note: I can't make it an abstract base class as implementors of IHaveObjects may already have a base class.)
Now I want to add a new method to the interface, so that one implementer of the interface can have special behaviour for it. Ideally I would do something like this:
public interface IHaveObjects
{
object firstObject();
object firstObjectOrFallback()
{
return firstObject();
}
}
then go to that one implementor of the interface and give it the override:
public class ObjectHaverPlus : IHaveObjects
{
public override object IHaveObjects.firstObjectOrFallback()
{
return firstObject() ?? getDefault();
}
}
However it is forbidden in C# to provide a method body in an interface, and I would like to avoid going to every single implementer of IHaveObjects to drop in a definition of firstObjectOrFallback(). (Imagine if there are hundreds or thousands)
Is there a way to do this without lots of copy paste?
How about introducing a second interface which inherits from IHaveObjects.
Than you only have to change these classes, which need the new interface with the new method.
This looks like:
interface I1
{
void Method1();
}
interface I2 : I1
{
void Method2();
}
That's the problem with interfaces - they don't have any default implementation so any changes to them are breaking changes - i.e. code needs to be modified to work with new version of interface.
Since your implementations already have base classes on their own - you cannot turn it into abstract class, nor does C# have multiple class inheritance.
What you can do is to think - is it really a method on interface? Or could it be implemented as an extension method on interface (didn't try that but I suppose it will work just fine)?
If it is a method on interface and it should stay there - you may think of breaking this interface into two parts, second inheriting from the first (IHaveObjectsAndSupportDefault : IHaveObjects) and use this interface where default value is truly needed (like some other answers indicate).
I may have misunderstood your question, but why not use a second interface, something like:
public interface IHaveObjectsEnhanced
{
object FirstObjectOrFallback();
}
Then you could implement the first and second interface:
public class ObjectHaverPlus : IHaveObjects, IHaveObjectsEnhanced
{
public object FirstObject()
{
}
public object FirstObjectOrFallback()
{
return FirstObject() ?? GetDefault();
}
}
There must be something fundamental about interfaces/generics I have not yet learned. I hope to learn it now.
Here is the scenario:
I have this interface and class:
public interface IInterface
{
string TestValue { get; set; }
}
public class RealValue: IInterface
{
public string TestValue { get; set; }
}
If I create a method like this it compiles just fine:
public class RandomTest: IMethodInterface
{
public IInterface GetRealValue()
{
RealValue realValue = new RealValue();
return realValue;
}
}
Note that I am returning an object that implements the interface.
Now, if I add to the RandomTest class a method that returns list then it does not work anymore:
public List<IInterface> GetRealValues()
{
List<RealValue> realValues = new List<RealValue>();
return realValues; // ERROR Here <- says it can't convert to a List<IInterface>
}
So, my guess is that generics can't figure this out, but why?
Is there a way around this? What do you do when the return value of the method above is locked because you are implementing an interface like this:
public interface IMethodInterface
{
IInterface GetRealValue();
List<IInterface> GetRealValues(); // Can't just convert the return types to a concrete
// class because I am implementing this. This
// interface is in a separate project that does not
// have the concrete classes.
}
Is there any hope? What would you do?
The reason for this is that List<RealValue> is a specific type, which does not inherit List<IInterface>, so it cannot be converted.
However, in .NET 4.0 you're in luck. The interface IEnumerable<out T> specifies that T can be the class, or a base class, so you can change your method to:
IEnumerable<IInterface> GetRealValues();
on .NET 4.0. Note that this only works because IEnumerable has the out keyword specified on the template parameter.
The out keyword means two things:
The type before which you put the out keyword can only be used for types that go out of the class. So, public T MyMethod() is allowed, but public void MyMethod(T myParam) is not allowed, because this goes into the class;
Because of this restriction, .NET knows that T can be cased to everything that inherits from T. Because of the restriction, this is guaranteed to be a safe operation.
Note that if you could convert List<RealValue> to List<IInterface> you could call .Add(anyObjectImplementingIInterface) which cannot work.
You can, however, use .Cast<IInterface>().ToList().
A List<RealValue> cannot be used in place of a List<IInterface>. If it was permitted, the caller would be able to Add an IInterface to the returned list that is of a type other than RealValue.
I've made a test case to illustrate the problem I've run into.
The first assert passes, but the second and third both fail.
Is there a way to check either of the two failing conditions k in a different way that will work? It would be OK if it's not terribly fast as I intend to cache the results on a per-type basis.
public interface IParentInterface
{
}
public interface IChildInterface : IParentInterface
{
}
public class ParentClass<T> where T: IParentInterface
{
}
public class ChildClass : ParentClass<IChildInterface>
{
}
public class TestClass
{
public ChildClass Property { get; set; }
}
[TestFixture]
public class ScratchPad
{
[Test]
public void Assignabl()
{
var tc = new TestClass();
var tct = tc.GetType();
var pi = tct.GetProperty("Property");
Assert.IsNotNull(pi);
Assert.IsTrue(typeof(ParentClass<IChildInterface>).IsAssignableFrom(pi.PropertyType));
Assert.IsTrue(typeof(ParentClass<>).IsAssignableFrom(pi.PropertyType));
Assert.IsTrue(typeof(ParentClass<IParentInterface>).IsAssignableFrom(pi.PropertyType));
}
}
It is by design that your second assertion fails. When you write
public class ParentClass<ParentInterface>
it actually means that "ParentInterface" is now a symbol for a type argument (doing that is so confusing that, indeed, it totally confused you).
Writing
public class ChildClass : ParentClass<ChildInterface>
then sets yout type argument (yeah, the one named "ParentInterface") to the type ChildInterface. Hence, Childclass is only assignable to ParentClass<ChildInterface>.
Lastly, you should ensure that you follow conventions when definining type arguments, it will confuse you a lot less, e.g.
public class ParentClass<T>
marking interfaces with "I" will also greatly enhance understanding, e.g.
interface IParent { }
interface IChild : IParent { }
I suspect that that which you want is not possible until we get c# 4.0:
Parent<IChild>
is not assignable to
Parent<IParent>
There is currently no co/contravariance for generics.
Isn't this the covariance/contravariance thing?
Then it's just something C# currently does not support, but C# 4.0 might.
You can't, because C# 3.0 does not support variance of this kind. In C# 4.0, you should be able to.
Using another example, say you had a List<ParentInterface>, and could assign it to a List<ChildInterface>:
List<ParentInterface> parentList = List<ParentInterface>();
List<ChildInterface> childList = parentList;
The problem is that the internal storage for parentList is for ParentInterface types. If you derived another interface from ChildInterface:
public interface ParentInterface2 : ChildInterface {}
And then tried to add it to childList like so:
childList.Add(new ParentInterface2Implementation());
You would get an exception, since childList is really a List<ParentInterface> and can only store implementations of ParentInterface, which ParentInterface2 is not.