We have a problem with the usage of generics.
We have a generic collection of generic keyvalue pair which is defined as follows
public class KeyValueTemplate<K, V> : IGetIdentifier<K>
{
//...
}
public class KeyValueListTemplate<K, V> : ObservableCollection<KeyValueTemplate<K, V>>
{
//....
}
public class KeyValueStringListTemplate : KeyValueListTemplate<string,string> { }
We are using this in the code as follows
public class test
{
public KeyValueStringListTemplate SetValuesList{get;set;}
public ObservableCollection<IGetIdentifier<string>> GetList()
{
return SetValuesList;
}
}
The complier is not accepting this. The error is
Cannot convert type 'KeyValueStringListTemplate' to 'System.Collections.ObjectModel.ObservableCollection<IGetIdentifier<string>>
Why?? Both the types are same to me.
This line
public class KeyValueListTemplate<K, V> : ObservableCollection<KeyValueTemplate<K, V>>
defines a new type, KeyValueListTemplate, that is a subtype of ObservableCollection, so they are different types. KeyValueListTemplatecan be safely converted to ObservableCollection, because it has a superset of ObservableCollection's functionality (by Liskov Substitution Principle), but the opposite conversion is not safe.
Its a matter of covariance in generics, which was not exposed to c#/vb.net before .net 4.
While it seem trivial that you can do this:
IEnumerable<string> strings = new List<string>();
// An object that is instantiated with a more derived type argument
// is assigned to an object instantiated with a less derived type argument.
// Assignment compatibility is preserved.
IEnumerable<object> objects = strings;
which is what your code is doing at the bottom line, it wasnt supported up to .net 4
The article i linked to explanis how to implement it and how it works.
Related
I have a question on typing and contra/covairance.
Given the following classes
public class BoardItemsHolderRepository<THolder, TBoardItem> : DataRepository<IList<THolder>>
where TBoardItem : BoardItem
where THolder : IBoardItemHolder<TBoardItem>
{
}
public interface IDataRepository<T> : IDataGetRepository<T>, IDataSetRepository<T> where T : class
{
}
public interface IDataGetRepository<out T> where T : class
{
IObservable<T> GetObservableStream();
IObservable<T> GetMostRecent();
}
public interface IDataSetRepository<in T> where T : class
{
void Set(T value);
}
public abstract class DataRepository<T> : IDataRepository<T> where T : class
{
..implementation details
}
public class ConstructHolder : IBoardItemHolder<Construct>
{
..implementation details
}
Given the above 3 files, can someone explain to me why is the following happening?:
IDataGetRepository<IList<IBoardItemHolder<Construct>>> wontCompile = new BoardItemsHolderRepository<ConstructHolder, Construct>(); //illegal
IDataGetRepository<IList<ConstructHolder>> compile = new BoardItemsHolderRepository<ConstructHolder, Construct>(); //legal
I can't understand why implicit casting for the first line would not work, as the following line compiles(as expected)
IBoardItemHolder<Construct>> compile = new ConstructHolder();
Let's expand the right hand side of the illegal line step by step. First, we start with
BoardItemsHolderRepository<ConstructHolder, Construct>
This is a DataRepository<IList<THolder>>, so the above is a kind of:
DataRepository<IList<ConstructHolder>>
which in turn is IDataGetRepository<T>, so the above is a kind of:
IDataGetRepository<IList<ConstructHolder>>
IDataGetRepository<T> is covariant on T. Recall exactly what this means: If U is a subtype of T, then IDataGetRepository<U> is a subtype of IDataGetRepository<T>. For example, IDataGetRepository<Cat> is a subtype of IDataGetRepository<Animal>, and so an instance of the former type can be assigned to a variable of the latter type.
However, IDataGetRepository<IList<ConstructHolder>> is not a subtype of IDataGetRepository<IList<IBoardItemHolder<Construct>>> and so cannot be assigned to it. Why? Because IList<ConstructHolder> is not a subtype of IList<IBoardItemHolder<Construct>>! IList<T> is invariant on T!
So what you are trying to do violates type safety, according to the type-checker. Maybe try using a IEnumerable rather than IList?
I believe this is the only way to achieve what I want but I wanted to put this out there to see if there's a solution that doesn't require using dynamic/reflection.
I have the following hierarchy of types, stripped to the bare essentials to demonstrate the point:
// Validators:
public abstract class Validator<T> { }
public class RequiredValidator<T> : Validator<T> { }
// Fields:
public abstract class Field { }
public abstract class Field<T> : Field
{
public void AddValidator(Validator<T> validator) =>
Console.WriteLine($"Added validator {validator.GetType()}");
}
public sealed class ValueField<T> : Field<T> { }
public sealed class ComputedField<T> : Field<T> { }
...many other field types that inherit Field<T>
This is an example usage of the fluent interface I want to achieve:
ValueField<string> field1 = new ValueField<string>().Required();
The Required() method must be available on all types that inherit Field<T>.
This is what I've come up with:
public static class Extensions
{
public static TField Required<TField, T>(this TField field) where TField : Field<T>
{
field.AddValidator(new RequiredValidator<T>());
return field;
}
public static TField DynamicRequired<TField>(this TField field) where TField : Field
{
DynamicAddRequiredValidator((dynamic)field);
return field;
}
private static void DynamicAddRequiredValidator<T>(Field<T> field)
{
field.AddValidator(new RequiredValidator<T>());
}
}
void Main()
{
// This is desired API usage but results in error:
// The type arguments for method 'Extensions.Required<TField,T>(TField)' cannot be inferred from the usage.
ValueField<string> field1 = new ValueField<string>().Required();
// This works but the user shouldn't have to specify types like this, makes it very annoying to use:
ValueField<string> field2 = new ValueField<string>().Required<ValueField<string>, string>();
// This works but requires dynamic:
ValueField<string> field3 = new ValueField<string>().DynamicRequired();
}
Am I missing a way of achieving this which avoids using dynamic based code?
Generics in C# are an all or nothing. You either pass all, like you've done, or none. It must be designed in a way that all arguments can be inferred. For what you're doing you can just use Field<T> instead of TField<T>, removing that generic type parameter; although it may not be as ideal. There are other ways... Some FLUENT designs return new types that contain the generics as properties allowing you to move forward but your continuation would need the logic of using that continue type as well. It gets a bit confusing but I feel you understand. If not let me know.
It would be nice if the where constraint could also help infer the types but it doesn't. Eric Lippert recently helped me understand that C# tries to infer the generic parameters only and if that can't be inferred it fails. The where constraint is only to limit the generic type to a base and inform developers. Although it does feel like we could also infer based on constraints, since we are basing the types, C# doesn't. Eric has an opinion about not doing so, which I'm sure is more than I understand ATM. Either way, there you have it.
For "extendable" fluent interface, we use following trick in Java (you can try, if it's possible in C# too):
public class Field<L extends Field<L, V>, V> {
public L required() {
//...
return (L) this;
}
}
public class ValueField<V> extends Field<ValueField<V>, V> {
}
Now you can call what you need:
ValueField<String> v = new ValueField<String>().required();
It's thanks to additional type parameter of Field which delegates specific return type of the fluent methods to children.
I cant seem to find anything that explicitly states this should never be done, not can i find a recommended method for doing it. so I am beginning to thing I am on an entirely wrong track here...
I am trying to overload a function based on return type in an interface. Basically I have 15 functions in an interface, 9 of them have the same name/params but different return type, I am trying to isolate this so I dont have to write 15 functions in the interface, I would just like a few..
public interface IController
{
IEnumerable<T> Fetch<T>();
}
from here I want to do implementations such as...
public IEnumerable<T> Fetch<T>() where T : *class*
{
return dbContext.*clas*.ToList();
}
however I recieve a compilation error of...
Error 1 The constraints for type parameter 'T' of method 'Controllers.Controller.Fetch<T>()' must match the constraints for type parameter 'T' of interface method 'IController.Fetch<T>()'. Consider using an explicit interface implementation instead.
anyone have any ideas on this one...
You can't do this because this implementation conflicts with the Liskov Substitution principle.
A method can only become more wide (accept more) than the the classes/interfaces above in the type hierarchy.
Now C# does not fully support the Liskov Substition principle (in the sense that widening parameters is not allowed). But it means for instance that if a method
public class Foo {
void Bar (T parameter);
}
is defined in the first level, that method cannot be override with
public class SubFoo : Foo {
void Bar (SubT parameter);
}
This is because one can call the Bar method of a SubFoo on the Foo level. And the Foo level has a contract that it accepts T. So making the types more narrow is not an option.
If one thus moves down in the class hierarchy one notices that:
return types become more narrow; and
parameters become wider
C# however supports variance/covariance on the interface level. If T is thus only used to specify the output type, one can indeed make T more narrow. This is called variance. You can specify this as:
public interface Foo<out T> {
T GetValue ();
}
It means that Foo<T> is a subclass of Foo<SuperT>. The same for covariance:
public interface Foo<in T> {
void SetValue (T value);
}
Making a few assumptions...if you're talking about an EF dbContext, you can actually do this:
public IEnumerable<T> Fetch<T>() where T : class
{
return dbContext.Set<T>().ToList();
}
More generally, you can do something like this, where the generic method delegates to various implementation methods for the different types:
public IEnumerable<T> Fetch<T>() where T : class
{
if (typeof(T) == typeof(X)) return FetchX();
//Handle other types here...
}
As Servy pointed out, to implement the above you would also need to modify your interface to include the class constraint (assuming you need it):
public interface IController
{
IEnumerable<T> Fetch<T>() where T: class;
}
I keep seeing this error, over and over again:
Cannot convert from Item<Foo> to Item<IFoo>.
This is clearly nonsense; an object of type Item<Foo> is statically guaranteed to be able to do absolutely everything that an Item<IFoo> can do (and possibly more), so why is the compiler refusing to accept my perfectly valid code?
I have a method that accepts an Item<IFoo> as an argument. For some reason, it refuses to accept an Item<Foo> as input, even though Foo implements IFoo. This makes no sense at all. I can pass a Foo in place of an IFoo, but I can't pass an Item<Foo> in place of an Item<IFoo>. Why?
public class Item<T>
{
public readonly int ID;
public readonly T Data;
...
}
public void ProcessItem(Item<IFoo> item)
{
Console.WriteLine(item.ID);
}
ProcessItem(new Item<Foo>());
Classes in C# are invariant, so depending on your requirements you'll have to create an interface and implment that:
public interface IItem<out T> { ... }
public class Item<T> : IItem<T> { ... }
IItem<IFoo> item = new Item<Foo>();
Note that it is not necessarily safe to assign a Class<Subtype> to a Class<Basetype>. A common example is List<T>:
List<object> l = new List<string>(); //won't compile
l.Add(3);
C# only allows variance annotations on interfaces and delegates, and only when it is safe to do so.
I'm working on a small class library at work, and it naturally involves using generics for this task. But there is this thing that I don't really understand with generics:
Why would I need to use generic type parameters, and then constrain the the type parameter to a specific base class or interface.
Here's an example to what I mean:
public class MyGenericClass<T> where T : SomeBaseClass
{
private T data;
}
And here's the implementation without generics
public class MyClass
{
private SomeBaseClass data;
}
Are these two definitions the same (if yes, then i don't see the advatage of using generics here)?
If not, what do we benefit from using generics here?
As with almost all uses of generics, the benefit comes to the consumer. Constraining the type gives you the same advantages that you get by strongly typing your parameter (or you can do other things like ensure that there's a public parameterless constructor or ensure that it's either a value or reference type) while still retaining the niceties of generics for the consumer of your class or function.
Using generics also, for example, allows you to obtain the actual type that was specified, if that's of any particular value.
This example is a little contrived, but look at this:
public class BaseClass
{
public void FunctionYouNeed();
}
public class Derived : BaseClass
{
public void OtherFunction();
}
public class MyGenericClass<T> where T: BaseClass
{
public MyGenericClass(T wrappedValue)
{
WrappedValue = wrappedValue;
}
public T WrappedValue { get; set; }
public void Foo()
{
WrappedValue.FunctionYouNeed();
}
}
...
var MyGenericClass bar = new MyGenericClass<Derived>(new Derived());
bar.Foo();
bar.WrappedValue.OtherFunction();
The difference is that the former defines the new class as a specific type; the latter simply defines a plain class with a field of that type.
It's all about type safety. Using generics you can return a concrete type (T) instead of some base type which defines the API you need in your generic class. Therefore, the caller of your method won't have to cast the result to the concrete type (which is an error-prone operation).
The main difference is in usage. In the first case, the usage can have:
MyGenericClass<SomeDerivedClass> Variable
Variable.data.SomeDerivedProperty = X
And so that when you use that class, you can still access anything from SomeDerivedClass without casting back to it.
The second example will not allow this.
MyClass.data = SomeDerivedClassInstance
MyClass.data.SomeDerivedProperty = X //Compile Error
((SomeDerivedClass)MyClass.data).SomeDerivedProperty = X //Ewwwww
You will have to cast back up to the SomeDerivedClass (which is unsafe) to use something specific to the derived class.
I don't think that there is a huge amount of difference except that the generic version is constraining your Class, whereas the second is just a constraint on a member of the class. If you added more members and methods to your first Class, you would have the same constraint in place.