Cannot convert generic object - c#

The following does not compile on line fm.AddFoo(new StringFoo()); with the error message:
Argument 1: cannot convert from 'ClassLibrary2.StringFoo' to 'ClassLibrary2.IFoo'
This seems logical to me since string inherits from object.
public interface IFoo<T>
{
void Handle(T value);
}
public class StringFoo : IFoo<string>
{
public void Handle(string value)
{ }
}
public class ObjectFoo : IFoo<object>
{
public void Handle(object value)
{ }
}
public class FooManager
{
private readonly List<IFoo<object>> _foos;
public FooManager()
{
_foos = new List<IFoo<object>>();
}
public void AddFoo(IFoo<object> foo)
{
_foos.Add(foo);
}
}
public class Bad
{
public Bad()
{
var fm = new FooManager();
fm.AddFoo(new StringFoo()); \\ This does not compile
}
}
Thanks

Although it may seem like IFoo is a subclass of IFoo it is not. When you close IFoo<> to a specific type is is not creating a subclass of IFoo from IFoo, they are seperate and distinct types with no common hierarchy.

If you could make your IFoo<> interface covariant it would work, that is if you were allowed to change the declaration of it into:
public interface IFoo<out T>
(note the out). Because with covariance any IFoo<string> would also be an IFoo<object> because string is a reference type and derives from object.
But: A member of IFoo<>, the Handle method, uses the type parameter in a contravariant manner. So your interface cannot be declared covariant (out). (It could be declared contravariant (in) but that goes in the wrong direction for your example above.)
Read up on covariance and contravariance in generics.
The fundamental problem here is that your StringFoo handles only strings. Therefore it can never be used as an IFoo<object> because then you could pass for example a Giraffe instance (Giraffe derives from object, so a Giraffe is an object) into the StringFoo, and that is impossible when its Handle takes a string.

Related

Cast instance of generic type to "template" instance

This might be a silly question and I don't really need this for anything but I was just curious...
The best way to describe it is using a example so here it is:
using System;
namespace GenericExample
{
public interface IFoo { }
public interface IFoo2 { }
public class Foo1: IFoo , IFoo2 { }
public class Foo2 : IFoo, IFoo2 { }
public class MyGeneric<T> where T : IFoo , IFoo2, new() { }
internal class Program
{
public static void Main(string[] args)
{
MyGeneric<Foo1> obj1 = new MyGeneric<Foo1>();
MyMethod(obj1);//I can treat obj1 as MyGeneric<T> in MyMethod
MyGeneric<Foo2> obj2 = new MyGeneric<Foo2>();
//But can I use is as MyGeneric<T> in this method???
//MyGeneric<?> obj3 = null;
//obj3 = (MyGeneric<?>)obj1;
//obj3 = (MyGeneric<?>)obj2;
Console.ReadLine();
}
public static void MyMethod<T>(MyGeneric<T> arg) where T : IFoo, IFoo2, new()
{
}
}
}
I don't think it is possible to treat obj1 as MyGeneric< T> in Main
but at the same time it feels strange since I can pass it as a MyGeneric< T> argument
You cannot cast it to MyGeneric<T> in Main because in the scope of Main there is no such type as T. Actually it's not really clear what you mean by
to treat obj1 as MyGeneric< T> in Main
When passing obj1 to MyMethod you don't "treat it as MyGeneric<T>". It is the compiler which infers the type of T for you. It knows that T is Foo1 here and translates your call
MyMethod(obj1);
to
MyMethod<Foo1>(obj1);
So the type of the parameter arg inside of MyMethod will at runtime also be MyObject<Foo1>, not an unspecified MyObject<T>.
There is no common base-type for MyGeneric and MyGeneric, so I assume the answer is no. In contrast to Java generics in C# are strongly typed types and not just placeholders, so they donĀ“t have anything in common - except a name. However actually they are different types, think of them as just MyGeneric<T1> being a type Foo and MyGeneric<T2> being Bar.
A way around this is to define a non-generic version of your generic class:
public class Foo1 { }
public class MyNonGeneric { }
public class MyGeneric<T> : MyNonGeneric where T : new() { }

Parameter must be input-safe error

Here is a piece of my code:
public interface IA<in TInput>
{
void Method(IB<TInput> entities);
}
public interface IB<in T> { }
I can't figure out why I get following compile error:
"Parameter must be input-safe. Invalid variance: The type parameter |TInput| must be contravariantly valid on "IB< in T>".
Any help will be appreciated.
The designator of contravariance in C# (i.e. in) is intuitive only at the immediate level, when you make a method that "takes in" a parameter of generic type. Internally, however, contravariance means an inversion of a relation (Q&A with an explanation) so using in inside IA makes it incompatible with IB.
The problem is best illustrated with an example. Consider class Animal and its derived class Tiger. Let's also assume that IB<T> has a method void MethodB(T input), which is called from IA's Method:
class A_Impl<T> : IA<T> {
T data;
public void Method(IB<TInput> entities) {
entities.MethodB(data);
}
}
Declaring IA<in TInput> and IB<in TInput> means that you can do
IA<Animal> aForAnimals = new A_Impl<Animal>();
IA<Tiger> aForTigers = aForAnimals;
IA<in TInput> has a method that takes IB<TInput>, which we can call like this:
aForTigers.Method(new B_Impl<Tiger>());
This is a problem, because now A_Impl<Animal> passes an Animal to MethodB of an interface that expects a Tiger.
You would have no problem with IB<out T>, though - both with covariance and contravariance:
public interface IB<out T> {
// ^^^
}
// This works
public interface IA<in TInput> {
void Method(IB<TInput> x);
}
// This works too
public interface IC<out TInput> {
void Method(IB<TInput> x);
}

C# Generics, interfaces and inheritance

I've two interfaces:
public interface IAmA
{
}
public interface IAmB<T> where T : IAmA
{
}
And two classes implementing these interfaces like this:
public class ClassA : IAmA
{
}
public class ClassB : IAmB<ClassA>
{
}
When trying to use these classes as shown:
public class Foo
{
public void Bar()
{
var list = new List<IAmB<IAmA>>();
list.Add(new ClassB());
}
}
I get this compiler error:
cannot convert from 'ClassB' to 'IAmB<IAmA>'
I know I can make the compiler happy using:
public class ClassB : IAmB<IAmA>
{
}
But I need to be able to be the Type parameter for IAmB<> in ClassB an implementation of IAmA.
The quick answer is that you can do what you ask by declaring the type parameter of IAmB<T> as covariant, only if the type is used as a return type:
public interface IAmB<out T> where T : IAmA
{
T SomeMethod(string someparam);
}
out T means that you can use a more specific type than then one specified in the constraints.
You won't be able to use T as a parameter. The following won't compile:
public interface IAmB<out T> where T : IAmA
{
void SomeMethod(T someparam);
}
From the documentation
You can use a covariant type parameter as the return value of a method that belongs to an interface, or as the return type of a delegate. You cannot use a covariant type parameter as a generic type constraint for interface methods.
This isn't a compiler quirk.
Assuming you could declare a covariant method parameter, your list would end up containing some objects that couldn't handle an IAmB<IAmA> parameter - they would expect an input of ClassA or more specific. Your code would compile but fail at runtime.
Which begs the question - why do you want to use IAmB<ClassA> ?
You should think about before using this though, as there may be other, more suitable ways to address your actual problem. It's unusual to use a generic interface implementing a concrete type but trying to use it as if it were implementing another interface.
You can check the MSDN documentation's section on Covariance and Contravariance as well as Eric Lippert's an Jon Skeet's answers to this SO question: Difference between Covariance and Contravariance
Fast answer : make the generic type covariant (see msdn) in your interface
public interface IAmB<out T> where T : IAmA
{
}
this will resolve the compiler problem.
But this won't answer the why asked by Panagiotis Kanavos !
The trick is making the type constraint T on IAmB<T> covariant, with the out keyword:
public interface IAmB<out T> where T : IAmA
{
}
This allows you to use a more specific type than originally specified, in this case allowing you to assign an IAmB<ClassA> to a variable of type IAmB<IAmA>.
For more information, see the documentation.
I just tell why this error reported.
if your IAmB has a method
public interface IAmB<T> where T : IAmA
{
void foo(T p);
}
public class ClassB : IAmB<ClassA>
{
void foo(ClassA p)
{
p.someIntField++;
}
}
and we have another class
public class ClassC : IAmB<ClassA2>
{
void foo(ClassA2 p)
{
p.someOtherIntField++;
}
}
and we assume List<IAmB<IAmA>>.Add(T p) implement like this
IAmA mParam = xxxx;
void Add(IAmB<IAmA>> p){
p.foo(mParam);
}
thinking all compile OK. you pass a ClassB instance to List.Add, it becomes
void Add(IAmB<IAmA>> p){
//p is ClassB now
p.foo(mParam);//COMPILER CAN NOT MAKE SURE mParam fit ClassB.foo
}
It can be solved using Contravariance and Covariance.
public interface IAmA
{
}
**public interface IAmB<out T> where T : IAmA
{
}**
public class ClassA : IAmA
{
}
public class ClassB : IAmB<ClassA>
{
}
public class Foo
{
public void Bar()
{
var list = new List<IAmB<IAmA>>();
**list.Add(new ClassB());**
}
}
Now you don't get compiler error. Compiler is happy.

Generic Constraint to allow casting from interface to implementation

I have a small class that implements a dictionary that maps from the type of an interface to an implementation of that interface that extends from a base class. Unfortunately the abstract base class does not implement the interfaces, so once in the dictionary, there seems to be no way to associate the two. There is another method in this class that is dependent on storing the objects as BaseClass (in fact, most of my class is dependent on that--the getter into the dictionary is somewhat of a convenience).
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (!(base is T)) // How to get rid of this check?
{
throw new ArgumentException("base does not implement " + typeof(T).Name);
}
this.dictionary.Add(typeof(T), base);
}
public T Get<T>()
{
BaseClass base;
this.dictionary.TryGetValue(typeof(T), out base);
return (T)(object)base; // How to get rid of (object) cast?
}
Are there any clever constraints I can use to remove the (base is T) check, the cast to object, or both?
Here is the class setup, for reference:
class BaseClass { }
interface IThing { }
class MyClass : BaseClass, IThing { }
dict.Add<IThing>(new MyClass());
IThing myClass = dict.Get<IThing>();
The only way to get the compile-time enforcement you're looking for would be if you have compile-type knowledge of the derived type being added.
For example, if you also specify a type parameter for the class being added then you could constrain that the class implement the interface type parameter:
public void Add<TInterface, TClass>(TClass #base)
where TClass : BaseClass, TInterface {
this.dictionary.Add(typeof(TInterface), #base);
}
So you could do this:
MyClass ok = new MyClass();
dict.Add<IThing, MyClass>(ok);
But not this:
class MyClassNotIThing : BaseClass { }
MyClassNotIThing notOk = new MyClassNotIThing();
dict.Add<IThing, MyClassNotIThing>(notOk);
Aside from that, generic constraints don't offer a means by which to constrain that a known type (i.e. BaseClass) inherit from a generic type parameter.
Here is the solution I ended up using. There are a few tricks that can make the Add() safe without the check (see the link in a comment to cokeman19's answer), but I opted not to do that as I find this code a bit cleaner.
interface IThing { }
abstract class BaseClass
{
internal T AsInterface<T> where T : class
{
return this as T;
}
}
class MyClass : BaseClass, IThing { }
class DictionaryClass
{
private readonly Dictionary<Type, BaseClass> dictionary;
public void Add<T>(BaseClass base)
{
if (base is T)
{
dictionary.Add(typeof(T), base);
}
}
public T Get<T>() where T : class
{
return dictionary[typeof(T)].AsInterface<T>();
}
}
Note that this solution does allow calls like:
myClass.AsInterface<IThingItDoesntImplement>()
but this returns null and I made the function internal to prevent strange uses anyway.

Is it possible to invoke a generic argument's method in C#?

In C++, you can invoke method's from a template argument like so:
template<class T> class foo
{
T t;
t.foo();
}
But in C#, it looks like this is not possible:
class foo<T>
{
T t;
public void foo() {
t.foo(); // Generates a compiler error
}
};
I suppose this probably isn't possible in C#, is it?
You have discovered the difference between templates and generics. Though they look similar they are in fact quite different.
A template need be correct only for the type arguments that are actually provided; if you provide a T that does not have a method foo then the compilation fails; if you provide only type arguments that have a foo then compilation succeeds.
By contrast a generic must be correct for any possible T. Since we have no evidence that every possible T will have a method foo then the generic is illegal.
Yes, if you know that the generic type placeholder T implements a member from a base class or interface, you can constrain the type T to that base class or interface using a where clause.
public interface IFooable
{
void Foo();
}
// ...
public class Foo<T> where T : IFooable
{
private T _t;
// ...
public void DoFoo()
{
_t.Foo(); // works because we constrain T to IFooable.
}
}
This enables the generic type placeholder T to be treated as an IFooable. If you do not constrain a generic type placeholder in a generic, then it is constrained to object which means only object's members are visible to the generic (that is, you only see members visible to an object reference, but calling any overridden members will call the appropriate override).
Note: This is additionally important because of things like operator overloading (remember that operators are overloaded, not overridden) so if you had code like this:
public bool SomeSuperEqualsChecker<T>(T one, T two)
{
return one == two;
}
This will always use object's == even if T is string. However, if we had:
public bool SomeSuperEqualsChecker<T>(T one, T two)
{
// assume proper null checking exists...
return one.Equals(two);
}
This WOULD work as expected with string because Equals() is overridden, not overloaded.
So, the long and the short is just remember that an unconstrained generic placeholder does represent any type, but the only calls and operations visible are those visible on object.
In addition to interface/base class constraints, there are a few other constraints:
new() - Means that the generic type placeholder must have a default constructor
class - Means that the generic type placeholder must be a reference type
struct - Means that the generic type placeholder must be a value type (enum, primitive, struct, etc)
For example:
public class Foo<T> where T : new()
{
private T _t = new T(); // can only construct T if have new() constraint
}
public class ValueFoo<T> where T : struct
{
private T? _t; // to use nullable, T must be value type, constrains with struct
}
public class RefFoo<T> where T : class
{
private T _t = null; // can only assign type T to null if ref (or nullable val)
}
Hope this helps.
You need to add a type constraint to your method.
public interface IFoo {
void Foo();
}
public class Foo<T> where T : IFoo {
T t;
public void foo() {
t.Foo(); // Generates a compiler error
}
}
It is possible if you are willing to accept generic type constraints. This means that your generic type must be constrained to derive from some base class or implement some interface(s).
Example:
abstract class SomeBase
{
public abstract DoSomething();
}
// new() ensures that there is a default constructor to instantiate the class
class Foo<T> where T : SomeBase, new()
{
T t;
public Foo()
{
this.t = new T();
this.t.DoSomething(); // allowed because T must derive from SomeBase
}
}

Categories

Resources