Conversion of nested collections to interfaces - c#

Why? Surely I do not need a user defined conversion as List(T) is an IList(T) and HashSet(T) is an IEnumerable(T). Thanks.
Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.HashSet<string>>' to 'System.Collections.Generic.IList<System.Collections.Generic.IEnumerable<string>>'. An explicit conversion exists (are you missing a cast?)
class Program {
static IList<IEnumerable<string>> GetSet() {
return new List<HashSet<string>>();
}
}

Because IList<T> is invariant.
To illustrate why this is a problem, consider the following example:
An IList<T> offers for instance a method to Add(T object) an IEnumerable<string>, which would conflict with your constructor expression new List<HashSet<string>>(). It would imply that I could call your program.GetSet() and add a new ArrayList<string>(), but your constructed instance will not allow it, since it has a contract that it only contains HashSet<string> instances (what would you return when one asks the content of the GetSet() containing an ArrayList<T>?
The fact that the typeparameter is doubly nested doesn't matter. For instance IList<Object> is not a superclass of IList<FooClass> either.
This is not the case with IEnumerable<T> itself (meaning that IEnumerable<T> is a IEnumerable<SuperT> as well), since the only functionality of an IEnumerable<T> is to output values. Which is allowed due to the Liskov Substitution Principle.
The principle says that when walking down in a class hierarchy, the
return types can only become more general (super classes/interfaces)
and the parameter types can only become more specific (sub
classes/interfaces).
C# offers tools to deal with this principle (called variance) by using the in and out keywords in the generic type declaration.
For instance if you are sure that a Foo<SubT> is a Foo<T> as well, you can define this as:
public class Foo<out T> {
T getResult () {
//do something
}
}
In that case T is covariant with respect to Foo. In case a type parameter is only used as input, it can be further specified. For instance Bar<T> is clearly a special case of Bar<SubT> in the following definition:
public class Bar<in T> {
void setParameter(T parameter) {
//do something
}
}

I think what I was really needing is a simple explanation of variance - contravariance and covariance - in the context of C# generics which I have found here and here:
The error message did not really lead me to that but now I will summarise:
Contravariance
A generic class, which of course is a template for a class rather than a class definition, can be made contravariant using the in keyword. A contravariant class allows assignments from a base class instance to a derived class instance ie BorderCollie = Dog
public interface AllowAssignmentsFromBaseToDerived<in T>
Covariance
A generic class can be made covariant using the out keyword. A covariant class allows assignments from a derived class instance to a base class instance ie Dog = BorderCollie
public interface AllowAssignmentsFromDerivedToBase<out T>
Variance is supported for array types since C# 1.0 and delegate types since C# 2.0, as well as generic type arguments since C# 4.0.
Would be nice to have had more responses to cover more points that I have missed, still feel a bit under informed.
More info lifted from here:
How can I create variant generic interfaces and delegates myself?
The out keyword marks a type parameter as covariant, and the in
keyword marks it as contravariant. The two most important rules to
remember:
You can mark a generic type parameter as covariant if it is used only
as a method return type and is not used as a type of formal method
parameters.
And vice versa, you can mark a type as contravariant if it
is used only as a type of formal method parameters and not used as a
method return type.
interface IVariant<out R, in A>
{
// These methods satisfy the rules.
R GetR();
void SetA(A sampleArg);
R GetRSetA(A sampleArg);
// And these don’t.
// A GetA();
// void SetR(R sampleArg);
// A GetASetR(R sampleArg);
}
Also, if you extend a variant generic interface it is invariant by default. You would need to specify In or Out as required.
Finally, as my explanation will be woefully inadequate try Eric Lippert's blog

Related

convert generic type to base class

public class Base {...}
public class Complex: Base {...}
public class MyOtherClass<T> {...}
and a list of the two type
List<MyOtherClass<Complex>> listOfComplex
List<MyOtherClass<Base>> listOfBase
I want have a list
listOfComplex.Union(listOfBase)
but i cant convert generic of a type to a generic of another type even if Complex derive fro Base
It's possibble to have a list of a base class?
Although Complex derives from Base, there is no such relationship between MyOtherClass<Complex> and MyOtherClass<Base>. That is the reason why you cannot create an Union of the two lists. For the framework both generic types are completely different.
The solution now really depends on what exactly your class does. Check out the topic of covariance and contravariance here in Docs - these are two special cases in which you will be permitted to create conversions between the two generic types if the types either are input or output only.
You could also add custom cast or manually cast the items to the "base" type before doing the "union" operation.
Because that's how Covariance and Contravariance in Generics works, specifically invariance, it means that you can use only the type originally specified; so an invariant generic type parameter is neither covariant nor contravariant.
You can't assign an instance of List<Base> to a variable of type List<Complex> or in the opposite direction. Same applies to custom generic classes. There is no implicit conversion that compiler could use in order to convert types.
Even if you add generic type constraint. A<B> and A<C> are two different types with no conversion between them even if C is inherited from B (because AC is not inherited from AB)
#MartinZikmund has explained why it does not work. The resolution to this kind of problem is to either derive the generic classes from a non-generic base class or to let them implement a common interface.
public class MyOtherClassBase { }
public class MyOtherClass<T> : MyOtherClassBase { }
Then you can specify MyOtherClassBase as generic parameter to Union explicitly. Now, Union will expect inputs of type IEnumerable<MyOtherClassBase>. Lists of type List<MyOtherClass<T>> are assignment compatible to IEnumerable<MyOtherClassBase>.
var result = listOfComplex.Union<MyOtherClassBase>(listOfBase);
Note the out keyword in the declaration
public interface IEnumerable<out T> : System.Collections.IEnumerable
It makes the interface covariant. See also SO question <out T> vs <T> in Generics and especially Reed Copsey's answer.
You should specify in your generic that T is a class base on Type :
public class MyOtherClass<T> where T : Base {...}
T will be accepted only if derive from Base And Union will should work
Here some documentation about Generics, thanks to #Marie:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

Autofac: The type '...' is not assignable to service '...'.

Consider the following classes and interfaces:
interface IFactory<T>{}
class Factory<T> : IFactory<T>{ }
interface IEntity{}
class Entity : IEntity{ }
I would like Autofac to resolve IFactory<IEntity> to Factory<Entity> like this:
b.RegisterType<Factory<Entity>>().As<IFactory<IEntity>>();
But I get the following exception (abbreviated for clarity):
The type 'Factory`1[Entity]' is not assignable to service 'IFactory`1[[IEntity]]'
Why is that and how can the issue be resolved? Or am I trying something "wrong"?
I briefly looked into RegisterGeneric, but I don't think it applies here; also, because the above is just an example. In other cases I may want to define a different component for IFactory<IEntity>.
This isn't an Autofac issue - it's a matter of generic variance. You'd see exactly the same in a simple C# program:
public class Program
{
public static void Main()
{
IFactory<IEntity> factory = new Factory<Entity>();
}
}
Most generic interfaces are invariant - the type arguments have to match exactly. Some are covariant like IEnumerable<T>, allowing you to write:
IEnumerable<object> objects = new List<string>();
and some are contravariant like IComparer<T>, allowing you to write:
IComparer<string> = Comparer<object>.Default;
Covariant interfaces only allow their type parameters to come "out" of the implementation (e.g. via return types). Contravariant interfaces only allow their type parameters to go "into" the implementation (e.g. via regular parameters). It gets subtle when you have delegate parameters that themselves accept values etc, but we'll ignore that for now...
It sounds like your IFactory<T> should be covariant - so you just change the declaration like this:
interface IFactory<out T>{}
At that point, the code compiles and I'd hope that Autofac can handle it too. That does require that your interface never uses T as an input though. (We can't tell as you haven't shown any interface members.)
For more details on generic variance, see the MS documentation.

Generic classes - when to use and why

i understand what they are, I'm just wondering when is the best time to use them.
My first thought was - when we are building a (static) utility class which should perform certain operations on different data types.
Ergo, it is a good practice to use generic methods to avoid numerous overloads of a certain method? Please comment on this.
I have a small example class. It's just for the sake of an example.
public static class Math<T> where T : operator +, operator -
{
public static T Add(T a1, T a2)
{
return a1+a2;
}
public static T Subtract(T a1, T a2)
{
return a1 - a2;
}
}
Would this be a good usage of generic classes and methods, e.g I wish to add and subtract ints, doubles.. etc.. with the minimum amount of code ?
Why won't this compile? I've tried this as well as modifying the class signature:
public static class Math<T> where T : struct
I understand that I must specify whether the Type parameter is of reference or of value type.
I did that by specifying that T must be constrained as a value type, so why am I still getting error that the operator + and/or - cannot be applied to T (which should specifically be a value type)
No this wouldn't be a good use. Generics are to provide type-safe data structures without knowing the type. Generic constraints allow you to specify some semantics about the type, such as implementing an interface, having a default constructor, or being a class or struct.
Please see these MSDN articles:
An Introduction to C# Generics
Constraints on Type Parameters
.
It won't compile because the operator + parts are not valid constraints.
Being a value type does not infer operators such as + or -, it only infers value-type semantics (inherits object, is a value type, cannot be null, has a default constructor).
Generic Constraints
Generic constraints help the compiler give you more from your T. An unconstrained generic can only be proven to be object, so you only get access to object members on the argument.
If you state: public void Foo<T>() where T : new()
The compiler can prove that your type has a default public parameterless constructor. This is the purpose of constraints, it forces the types that can be party to the generic to conform to a contract.
There are various constraints, but as you have found there are some limitations. Interestingly, there are limitations in C# that do not exist in IL, as explored by Jon Skeet in his Unconstrained Melody library that exposes enum constraints to C#.
As written by others the operator+ isn't a valid constraint. If what you want is to make some generic math, you can use something like:
public static class Add<T>
{
public static readonly Func<T, T, T> Do;
static Add()
{
var par1 = Expression.Parameter(typeof(T));
var par2 = Expression.Parameter(typeof(T));
var add = Expression.Add(par1, par2);
Do = Expression.Lambda<Func<T, T, T>>(add, par1, par2).Compile();
}
}
public static class Math<T>
{
public static T Add(T a1, T a2)
{
return Add<T>.Do(a1, a2);
}
This will create and compile an Expression that does the operation and then cache it in a generic static class.
Sadly with this method you lose the static checking of you compiler (you could do something like:
object res = Math<object>.Add(new object(), new object());
and it would compile correctly. At runtime it would explode.)
In general you can't make a constraint asking for a specific method (static or non-static) or a specific property to be present (operators are like static methods) (with a single exception: the new() constraint that asks for a public parameterless constructor). What you can ask is for an interface to be implemented, or for a base class to be present, or for the generic parameter to be a class or a struct (where the two must be meant as "reference type" and "value type", and not simply as class and struct). Sadly there are no interfaces IAddable, ISubtractable, ... and even if you built them, int, double... wouldn't implement them, and to make it worse, in .NET you can't have generic specializations (a trick of C++ where you define a generic Math<T> and then you define special "cases" explicitly, like Math<int>, Math<double> and so on)
The obvious use case for generic classes is data structures which can then store any type of data without having to treat it all as instances of object. You probably use these all the time - IList<T>, IDictionary<K, V> etc. It lets you store things where you don't know the type when you're writing the structure while retaining type safety. The trick being that you also don't know anything about the type you're storing so you can't do much with it.
Thus generic constraints, which let you say something is a reference type or a value type, or has a parameterless constructor, or implements an interface. These come in useful when you're writing a generic class which has to do something with instances of the parameterised type. Might seem useless - why not just use an interface type as the parameter type and avoid generics altogether? Because generic constraints can force a parameter to conform to more than one interface - something you can't specify in a normal parameter type. Thus you can write a function:
public static void Frobnicate<T>(T thing)
where T : IList<int>, IDisposable
{
// ...
}
You can also stick a single base class name in there too. This is far, far more flexible than specifying concrete types. Sure you could create an interface which inherits from IList<int> and IDisposable but you can't retrofit all disposable lists of integers that might be out there to implement it.
You could also do it at runtime using reflection to inspect things, but this kind of thing is far better handled by the compiler, IMO.

Is there a syntax does a reversed type inference?

When I tried to answer the question:
Is it possible to get rid of the TClient generic type in the Service class
I found a strange usage that I've never designed something of this kind of uncompilable syntax, and following is a represent of what I encountered:
interface IGeneric<T> {
}
partial class SomeClass {
// won't compile
public static void SomeMethod<U>(Action<T> d) where T: IGeneric<U> {
}
}
And even if declared as:
class Concrete: IGeneric<object> {
}
partial class SomeClass {
public static void SomeMethod<U>(Action<IGeneric<U>> d) { // compiles
}
}
would not make the following code compile-able:
var d=default(Action<Concrete>);
SomeClass.SomeMethod(d); // won't compile
I'm not aware a syntax that works without both type parameters involved.
So I'm wondering is there a syntax does this kind of a reversed type inference? Or a workaround?
The simple answer is no. This isn't even initially about type inference - it's about type constraints. You can only add constrain a type parameter which is introduced in the same declaration. So this:
public static void SomeMethod<U>(Action<T> d) where T: IGeneric<U>
is invalid because you're trying to constrain T in terms of U, when it's U which was actually introduced in the method declaration. Indeed, T itself isn't a type parameter anywhere - but this would fail even if SomeClass were generic in T.
In many situations similar to this you can go via an extra static method in a non-generic type, to create an instance of a generic type via type inference - but the specifics are usually that you've got two type parameters and you want to specify one of them explicitly.
One important point to note is that an Action<Concrete> simply is not an Action<IGeneric<object>>. For example, Concrete may expose some extra property which an Action<Concrete> could depend on - but given an Action<IGeneric<object>> you could easily call that with a different implementation of IGeneric<object>. Your existing SomeMethod tries to sort of work around that by specific Action<U> instead of Action<IGeneric<T>> - but at that point it's relatively hard to use the action. This is rarely (in my experience) a practical approach, even when type inference works.
As soon as you change to a genuinely covariant delegate (and assuming you're using C# 4), then unless you care about U you can simply use a different signature:
using System;
interface IGeneric<T> {}
class SomeClass
{
public static void SomeMethod<T>(Func<IGeneric<T>> d) {}
}
class Concrete: IGeneric<object> {}
class Test
{
static void Main()
{
var d = default(Func<Concrete>);
// This compiles fine
SomeClass.SomeMethod(d);
}
}
The problem is that you are trying to treat an Action<T> as being covariant in T but it isn't. In fact, it's contravariant.
For example, if you had a covariant delegate, like this.
delegate T CovariantCall<out T>();
You could easily do what you're asking.
CovariantCall<IGeneric<object>> covariant = default(CovariantCall<Concrete>);
Your first example doesn't compile because you've omitted the T in the declared type parameters list for the method. It's a better idea, though, and it works because the constraint only verifies and doesn't affect parameter variance, but you would then have to explicitly specify which parameters you're looking for and can't infer it.
public static void SomeMethod<T, U>(Action<T> d) where T: IGeneric<U>
{
...
}
SomeClass.SomeMethod<Concrete, object>(default(Action<Concrete>));
There are limits to what C# type inference is capable of, and this is one of them. You can't do what you're asking without explicitly specifying the types.

C# Type Conversion Error Despite Generic Constraint

Why, with a generic constraint on type parameter T of class P of "must inherit from A", does the first call succeed but the second call fail with the type conversion error detailed in the comment:
abstract class A { }
static class S
{
public static void DoFirst(A argument) { }
public static void DoSecond(ICollection<A> argument) { }
}
static class P<T>
where T : A, new()
{
static void Do()
{
S.DoFirst(new T()); // this call is OK
S.DoSecond(new List<T>()); // this call won't compile with:
/* cannot convert from 'System.Collections.Generic.List<T>'
to 'System.Collections.Generic.ICollection<A>' */
}
}
Shouldn't the generic constraint ensure that List<T> is indeed ICollection<A>?
This is an example of C#'s lack of covariance on generic types (C# does support array covariance). C# 4 will add this feature on interface types and also will update several BCL interface types to support it as well.
Please see C# 4.0: Covariance and Contravariance:
In this article I’ll try to cover one
of the C# 4.0 innovations. One of the
new features is covariance and
contravariance on type parameters that
is now supported by generic delegates
and generic interfaces. First let’s
see what does these words mean :)
The constraint has no effect on the problem; the issue is that you're passing a List in a parameter that requires ICollection--C# doesn't support covariance so you need to explicitly cast the list to an ICollection:
S.DoSecond((ICollection<A>) new List<T>()); // this call will be happy
You have strongly typed the parameter for DoSecond as type ICollection<A>. Despite the fact that T is of type A, at compile time there is no implicit cast between List<T> and ICollection<A>. You will either need to create the list and cast it to ICollection<A> when you call DoSecond, or make DoSecond a generic method itself.
NOTE: This type of implicit cast should be supported in C# 4.0, which will provide much improved co/contravariance over what C# 3.0 offers.

Categories