Generic Constraint to allow casting from interface to implementation - c#

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.

Related

c# .net 4.0 Covariant vs Contravariant

I'm trying to get something working and struggling with the below when using Contravariance. My understanding is Covariance is where you can return a derived type from a base type. Contravariance is where you can pass in a derived type from a base type as an argument into a class.
So I have the below interface (contravariant):
public interface IBase<in T> where T: BaseModel
{
void Process(T model);
}
I then have an abstract class
public abstract class Base<T>: IBase<T> where T: BaseModel
{
public virtual void Process(T model)
{
// throw new System.NotImplementedException();
}
}
and another concrete class
public class Parent: Base<ParentModel>
{
public override void Process(ParentModel model)
{
// throw new System.NotImplementedException();
}
}
Considering the generic type is only ever used as an input and not a return type, I don't see why I cannot do the below:
IBase<BaseModel> baseContravariant = new Parent();
// This doesn't compile. I will eventually have a list of IBase<BaseMode> to which I'd like to pass in different parent instances.
I have another example using covariance which is below and works fine.
public interface IBase<out T> where T : BaseModel, new()
{
T ProcessAndGet();
}
Abstract
public abstract class Base<T>: IBase<T> where T: BaseModel, new()
{
public virtual T ProcessAndGet()
{
var result = new T() as BaseModel;
// More shizzle here
return (T)result;
}
}
Concrete
public class Parent : Base<ParentModel>
{
public override ParentModel ProcessAndGet()
{
var x = base.ProcessAndGet();
return x;
}
}
Now I can do
IBase<BaseModel> baseInstance = new Base<BaseModel>();
IBase<BaseModel> derived = new Parent();
baseInstance = derived;
There's more code to the above examples but I've removed it for ease of reading (hopefully!) :-)
Contravariance in this case means that you need to pass in types that are of the specified type or one that is "more specialised" (=> derive from the base type).
Since your Parent implementation in your first example can only process ParentModel, it is invalid to pass in a BaseModel instance. Trying to do new Parent().Process(new BaseModel()) also would not compile. So it is invalid to cast it to IBase<BaseModel>. (assuming ParentModel is a subclass of BaseModel).
In this case the contravariance model is easier to reason about by thinking that an IBase<in T> "consumes a T". So an IBase<ParentModel> "consumes ParentModels". This means it can only be passed values that are instances of ParentModel or can be treated as one (effectively only subclasses).
In your second example you are using <out T>, which is "covariant". This can be described as "it produces instances of T". So a class that "produces" a ParentModel is automatically a "producer" of BaseModel as well: since ParentModel can be cased to BaseModel, IBase<ParentModel> can be casted to IBase<BaseModel> as well.

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() { }

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.

Cannot convert generic object

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.

Implementing C# Dictionary results in error: Does not have matching return type

I am trying to understand how C# implements the Dictionary. It seems to me that Dictionary is supposed to inherit from IEnumerable which requires the method implementation for:
IEnumerable GetEnumerator()
However, the C# Dictionary instead implements:
Dictionary<T>.Enumerator GetEnumerator()
Where Enumerator is a nested struct which inherits from IEnumerator.
I have created an example of this relationship:
public interface IFoo
{
IFoo GetFoo();
}
public abstract class Foo : IFoo
{
public abstract FooInternal GetFoo();
public struct FooInternal : IFoo
{
public IFoo GetFoo()
{
return null;
}
}
}
However, this doesn't compile, resulting in the following error:
Error 2 'Foo' does not implement interface member 'IFoo.GetFoo()'. 'Foo.GetFoo()' cannot implement 'IFoo.GetFoo()' because it does not have the matching return type of 'CodeGenerator.UnitTests.IFoo'. Foo.cs 14
Any thoughts on what I might be doing wrong here? How does C# implement the Dictionary? How would one make the example code compile similarly to the C# Dictionary?
You are missing an explicit interface implementation:
public abstract class Foo : IFoo
{
public abstract FooInternal GetFoo();
// start here
IFoo IFoo.GetFoo()
{
return GetFoo();
}
// end here
public struct FooInternal : IFoo
{
public IFoo GetFoo()
{
return null;
}
}
}
You are confusing two distinct interfaces, namely IEnumerable and IEnumerator.
The outer class, the dictionary class, implements IEnumerable. This involves that the outer class has a method GetEnumerator. This method returns an instance of the nested (inner) struct.
The inner struct implements IEnumerator. To implement IEnumerator you must have a MoveNext method and a Current property.
Besides, there's the issue of explicit interface implementation which is mentioned also by Andrey Shchekin's answer. This code is legal and similar to Dictionary<,>:
public interface IFoo // corresponds to IEnumerable
{
IBar GetBar();
}
public interface IBar // corresponds to IEnumerator
{
}
public class Foo : IFoo
{
// public method that has BarInternal as return type
public BarInternal GetBar()
{
return new BarInternal();
}
// explicit interface implementation which calls the public method above
IBar IFoo.GetBar()
{
return GetBar();
}
public struct BarInternal : IBar
{
}
}
It would also be possible to implement the IFoo "directly" (not explicitly) by a public method, but then the declared return type must match:
public class Foo : IFoo
{
// public method that directly implements the interface
public IBar GetBar()
{
return new BarInternal();
}
public struct BarInternal : IBar
{
}
}
The reason why Dictionary<,> isn't written in this simpler way, is that you get boxing of the nested struct, I guess.
Note that when you foreach through a Dictionary<,>, the C# compiler first searches for a public non-generic parameterless instance method with the exact name GetEnumerator. If such a method is found, it is used, and the compiler doesn't care about IEnumerable. Therefore, with a Dictionary<,>, the slightly more optimal public method which does not implement the interface, is used during foreach.
Explicit interface implementations are documented on MSDN. See Dictionary<TKey, TValue>.IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator (generic) and Dictionary<TKey, TValue>.IEnumerable.GetEnumerator (non-generic).

Categories

Resources