I have abstract base class like:
public abstract class CacheValueProviderBase<T> where T : ICacheItem
{
protected ConcurrentDictionary<int,T> dataList = new ConcurrentDictionary<int, T>();
public virtual void Add(T model){ // add code }
public virtual bool Remove(int id){ //remove code }
public abstract string getName();
public abstract void UpdateForceFromDataBase();
public abstract void UpdateForceFromCacheServer();
public virtual bool allowForUpdater
{
get
{
return true;
}
}
public virtual bool beforeUpdate()
{
return true;
}
}
I have multiple derived classes from this abstract class. The Slider_CacheValueProvider class below is used as an example.
public class Slider_CacheValueProvider : CacheValueProviderBase<Cache_Home_Slider_Model>
{
public override string getName()
{
return "Slider_Cache";
}
public override void UpdateForceFromCacheServer()
{ // updating from cache server
}
public override void UpdateForceFromDataBase()
{ // updating from database
}
}
Slider cache model:
public class Cache_Home_Slider_Model : ICacheItemID
{
public int ID { get; set; }
public string SlideImage { get; set; }
public string Link { get; set; }
}
All cache models depends ID property and implement this interface just for easy crup operation:
public interface ICacheItemID
{
int ID { get; set; }
}
Info: My caching mechanism has 2 steps. The first step is an internal cache. The second step is an external cache server.
I have cache updater. It is updating caches periodically which depends abstract class 'allowForUpdater' property. Firstly, I found all derived classes with this:
public static List<Type> CacheTypeList()
{
var type = typeof(CacheValueProviderBase<>);
return Assembly.GetExecutingAssembly().GetTypes().Where(i => !i.IsAbstract && !i.IsInterface &&
i.BaseType != null && i.BaseType.IsGenericType && i.BaseType.GetGenericTypeDefinition() == type
).ToList();
}
And iterating like this:
foreach (var item in CacheTypeList())
{
var cache= getCache(item);
if(cache.allowForUpdater && cache.beforeUpdate())
{
cache.UpdateForceFromCacheServer();
}
}
And the getCache method:
public static CacheValueProviderBase<ICacheItem> getCache(Type type)
{
var val = storeList.Find(i => i.Key == type).Value;
return (CacheValueProviderBase<ICacheItem>)val;
}
storeList is static list and include Slider_CacheValueProvider global on app.
The problem is the getCache method. When I try to cast it, I receive an exception. 'Unable to cast object of type ...' . Slider_CacheValueProvider inherited from base and slider model implement from ICacheItem. What is the problem? Why can't I cast?
Update 1:
Using 'out' keyword to abstract class, getting this error:
'Invalid variance modifier. Only interface and delegate type parameters can be specified as variant'.
So i change the abstract class with interface. Interface is :
public interface ICacheProvider<T> where T : ICacheItemID
{
DateTime LastModifiedTime { get; set; }
void Add(T model);
bool Remove(int id);
bool Update(T model);
T Where(Func<T, bool> expression);
void Clear();
int Count(int id);
IEnumerable<T> GetList();
void AddList(IEnumerable<T> model);
void RemoveList(IEnumerable<int> model);
void RemoveByFunc(Func<KeyValuePair<int, T>, bool> expression);
IEnumerable<T> WhereList(Func<T, bool> expression);
string getName();
void UpdateForceFromDataBase(bool updateCache = true);
void UpdateForceFromCacheServer();
bool allowForUpdater { get; }
bool beforeUpdate();
}
And current abstract class like this:
public abstract class CacheValueProviderBase<T> : ICacheProvider<T> where T : ICacheItemID
If i change interface to 'out T', getting error on Add,Update,AddList,RemoveByFunc. Error is:
"Invalid variance, The Type parameter 'T' must be contravariantly valid on ICacheProvider.Add(T) (or other method name) 'T' is a covariant. "
Update 2:
I changed my code. I created new interface for updater like this:
public interface ICacheUpdaterImplements
{
string getName();
void UpdateForceFromDataBase();
void UpdateForceFromCacheServer();
bool allowForUpdater();
}
I get this interface like this:
public static ICacheUpdaterImplements getCacheUpdaterImplements(Type type)
{
return (ICacheUpdaterImplements)storeList.Single(i => i.Key == type).Value;
}
And change updater code like this:
foreach (var item in CacheTypeList())
{
var updater= getCacheUpdaterImplements(item);
if(updater.allowForUpdater())
{
updater.UpdateForceFromCacheServer();
}
}
So, I see, I have wrong design. I changed code and resolve problem.
Neither of the answers given so far are correct. They are right that the problem is that your type is not covariant, but wrong in the proposed solution, which is illegal and will not compile.
Your example is very complicated, so let's look at a simpler example. If you have:
class Animal {}
class Giraffe : Animal {}
class Tiger : Animal {}
Then this conversion is legal:
IEnumerable<Giraffe> giraffes = new List<Giraffe>() { new Giraffe() };
IEnumerable<Animal> animals = giraffes;
This is a covariant conversion. A covariant conversion is a conversion where the justification for the conversion is "Giraffe is convertible to animal, therefore a sequence of giraffes is convertible to a sequence of animals". That is, a covariant conversion is one where an existing conversion justifies a more complex generic conversion.
However, this conversion is not legal:
IList<Giraffe> giraffes = new List<Giraffe>() { new Giraffe() };
IList<Animal> animals = giraffes;
Why is this conversion not allowed? Because it can be abused! We can now say
animals.Add(new Tiger());
The list of animals is still a list of giraffes. You cannot add a tiger to a list of giraffes. You can add a tiger to a list of animals. Therefore, "list of giraffes" is not a subtype of "list of animals", even though giraffe is a subtype of animal. IEnumerable<T> allows covariance because there is no way to insert a tiger into a sequence of giraffes. IList<T> does not allow covariance because there is a way to abuse it.
C# allows covariant conversions like the one you want under the following circumstances:
The generic type arguments involved in the covariant conversion -- that is, the stuff in the <> --- must all be reference types. You cannot, say, convert List<int> to IEnumerable<object> even though int is convertible to object. int is not a reference type.
The "outer" generic type that you are converting to must be an interface or a delegate type, not a class or a struct.
The interface or delegate must be declared as supporting covariance, and the compiler must be able to check that the declaration is valid and never produces a situation where you can put a tiger into a box that can only hold giraffes.
I do not know offhand how to redo your complicated logic to make it work the way you want. You might want to go with a less complicated solution that does not rely on generics so much.
Try this implementation, it should get you what you need... Since you are using generics quite extensively this is the way to go - but if I were you I'd give the whole construct of yours a second thought, since I assume you won't be able to call this method (only by using reflection)
public ICacheProvider<T> getCache<T>() where T : ICacheItem
{
var val = storeList.Single(i => i.Key == typeof(T)).Value;
return (ICacheProvider<T>)val;
}
Related
If I write a method accepting a parameter which derives from a BaseClass (or an interface), as far as I know there are two ways to achieve that:
void MyMethod<T>(T obj) where T : BaseClass { ... }
and
void MyMethod(BaseClass obj) { ... }
What are the differences between the two methods?
In this example there isn't a big difference between the two, you can access the same members inside the method and you can call it with the same derived classes. There is a runtime difference as a generic method is compiled for each type it is invoked with.
Where generics come in useful would be if you would return a value depending on T
With generics you could do the following
T MyMethod<T>(T obj) where T : BaseClass { ... }
MyMethod(derivedInstance).derivedProperty
Without this would be an error:
BaseClass MyMethod(BaseClass obj) { ... }
MyMethod(derivedInstance).derivedProperty // error
Note Although you mention constraining to a base class, it is worth mentioning that if you constrain not to a class, but to an interface, extra boxing will occur if the implementation is by a struct in the non generic version, this can have severe performance implications.
When T is constrained to a base class, there is not really much difference apart from what has already been stated.
When T is constrained to an interface, the difference can be huge:
int FrobNonGeneric(IFrobbable frob) { //... }
int Frob<T>(T frob) where T: IFrobbable { //... }
struct Frob: IFrobbable { ... }
FrobNonGeneric(new Frob()); //boxing!
Frob(new Frob()); //no boxing
Definitely the example you quoted does not make much difference other than run time execution performance as mentioned in other answers.
Leaving aside generic collections benefits (performance improvement by avoiding boxing/unboxing for example) which we all aware of and we use frequently - Generics also works great from a consumer perspective. For example, the below code snippet is self explanatory to visualize API usage flexibility from a consumer perspective :
interface IEntity
{
int Id {get;set;}
}
class Student : IEntity
{
int Id {get;set;}
string SubjectOpted {get;set;}
}
class Employee : IEntity
{
int Id {get;set;}
string DepartmentName{get;set;}
}
interface INonGenericRepository
{
IEntity Get(int id)
}
interface IGenericRepository<T> where T:Entity
{
T Get(int id)
}
class NonGenericRepository : IRepository
{
public IEntity Get(int id) {/*implementation goes here */
}
class GenericRepository<T> : IRepository<T>
{
public T Get(int id) {/*implementation goes here */
}
Class NonGenericStudentConsumer
{
IEntity student = new NonGenericFRepository().Get(5);
var Id = student.Id
var subject = student.SubjectOpted /*does not work, you need to cast */
}
Class GenericStudentConsumer
{
var student = new GenericFRepository<Student>().Get(5);
var Id = student.Id
var subject = student.SubjectOpted /*works perfect and clean */
}
A couple of other use cases promoting flexibility while using generics along with constraints are :
Lets say I want to ensure parameter passed to method implements IAdd and IMultiply and I have class which implements both IAdd,IMulitply like :
public class BusinessOpeartion<T> where T : IAdd, IMultiply{
void SomeBusinessOpeartion(T obj) { /*implementation */}
}
If I need to go via non generic approach, I am forced to create redundant dummy interface like :
interface IDummy : IAdd, IMultiply
public class BusinessOpeartion{
void SomeBusinessOpeartion(IDummy obj) { /*implementation */}
}
Isn't the former approach cleaner?
Also one more small thing just popped up while typing answer. In case you need to, how would you get new instance for parameter type inside method:
you cannot do
IDummy dummy = new IDummy(); /*illegal*/
But with generic you could have; T temp = new T(); provided there is constraint of new()
Also what if you need a default value for parameter type?
you cannot do
var default = default(IDummy); /*illegal*/
But with generic you could have; var default = default(T)
As was said, it matters only once you get a return value. Consider these cases:
BaseClass MyMethod(BaseClass)
DervivedClass temp = new DervivedClass();
//Error. My Method always returns a BaseClass. No implicit casting available
temp = MyMethod(temp);
Compare it to this:
T MyMethod<T>(T) where T : BaseClass
DervivedClass temp = new DerivedClass();
temp = MyMethod<DerivedClass>(temp);
Strong Typification is one of the best friends you have in .NET. Embrace it. Never try to avoid it. The opposite would be cases like we have in PHP and JavaScript: http://www.sandraandwoo.com/2015/12/24/0747-melodys-guide-to-programming-languages/
In the examples included in your question, there isn't much difference between the generic and the non-generic version. But here are some other examples of method signatures that can't be expressed without generics:
T MyMethod<T>(T obj) where T : BaseClass { ... }
void MyMethod<T>(T obj1, T obj2) where T : BaseClass { ... }
void MyMethod<T>(T obj, List<T> list) where T : BaseClass { ... }
ReSharper suggests me to make type parameter T contravariant by changing this:
interface IBusinessValidator<T> where T: IEntity
{
void Validate(T entity);
}
Into this:
interface IBusinessValidator<in T> where T: IEntity
{
void Validate(T entity);
}
So what is different between <T> and <in T>? And what is the purpose of contravariant here?
Let say I have IEntity, Entity, User and Account entities. Assuming that both User and Account have Name property that need to be validated.
How can I apply the usage of contravariant in this example?
So what is different between <T> and <in T>?
The difference is that in T allows you to pass a more generic (less derived) type than what was specified.
And what is the purpose of contravariant here?
ReSharper suggests to use contravariance here because it sees the you're passing the T parameter into the Validate method and wants to enable you to broaden the input type by making it less generic.
In general, contravariance is explained to length in Contravariance explained and in Covariance and contravariance real world example, and of course throughout the documentation on MSDN (there is a great FAQ by the C# team).
There is a nice example via MSDN:
abstract class Shape
{
public virtual double Area { get { return 0; }}
}
class Circle : Shape
{
private double r;
public Circle(double radius) { r = radius; }
public double Radius { get { return r; }}
public override double Area { get { return Math.PI * r * r; }}
}
class ShapeAreaComparer : System.Collections.Generic.IComparer<Shape>
{
int IComparer<Shape>.Compare(Shape a, Shape b)
{
if (a == null) return b == null ? 0 : -1;
return b == null ? 1 : a.Area.CompareTo(b.Area);
}
}
class Program
{
static void Main()
{
// You can pass ShapeAreaComparer, which implements IComparer<Shape>,
// even though the constructor for SortedSet<Circle> expects
// IComparer<Circle>, because type parameter T of IComparer<T> is
// contravariant.
SortedSet<Circle> circlesByArea =
new SortedSet<Circle>(new ShapeAreaComparer())
{ new Circle(7.2), new Circle(100), null, new Circle(.01) };
foreach (Circle c in circlesByArea)
{
Console.WriteLine(c == null ? "null" : "Circle with area " + c.Area);
}
}
}
How can I apply the usage of contravariant in this example?
Let's say we have our entities:
public class Entity : IEntity
{
public string Name { get; set; }
}
public class User : Entity
{
public string Password { get; set; }
}
We also have a IBusinessManager interface and a BusinessManager implementation, which accepts an IBusinessValidator:
public interface IBusinessManager<T>
{
void ManagerStuff(T entityToManage);
}
public class BusinessManager<T> : IBusinessManager<T> where T : IEntity
{
private readonly IBusinessValidator<T> validator;
public BusinessManager(IBusinessValidator<T> validator)
{
this.validator = validator;
}
public void ManagerStuff(T entityToManage)
{
// stuff.
}
}
Now, lets say we created a generic validator for any IEntity:
public class BusinessValidator<T> : IBusinessValidator<T> where T : IEntity
{
public void Validate(T entity)
{
if (string.IsNullOrWhiteSpace(entity.Name))
throw new ArgumentNullException(entity.Name);
}
}
And now, we want to pass BusinessManager<User> an IBusinessValidator<T>. Because it is contravariant, I can pass it BusinessValidator<Entity>.
If we remove the in keyword, we get the following error:
If we include it, this compiles fine.
To understand ReSharper's motivation, consider Marcelo Cantos's donkey gobbler:
// Contravariance
interface IGobbler<in T> {
void gobble(T t);
}
// Since a QuadrupedGobbler can gobble any four-footed
// creature, it is OK to treat it as a donkey gobbler.
IGobbler<Donkey> dg = new QuadrupedGobbler();
dg.gobble(MyDonkey());
If Marcelo had forgotten to use the in keyword in the declaration of his IGobbler interface, then C#'s type system wouldn't recognise his QuadrupedGobbler as a donkey gobbler, and so this assignment from the code above would fail to compile:
IGobbler<Donkey> dg = new QuadrupedGobbler();
Note that this wouldn't stop the QuadrupedGobbler from gobbling donkeys - for instance, the following code would work:
IGobbler<Quadruped> qg = new QuadrupedGobbler();
qg.gobble(MyDonkey());
However, you wouldn't be able to assign a QuadrupedGobbler to a variable of type IGobbler<Donkey> or pass it to some method's IGobbler<Donkey> parameter. This would be weird and inconsistent; if the QuadrupedGobbler can gobble donkeys, then doesn't that make it a kind of donkey gobbler? Luckily, ReSharper notices this inconsistency, and if you leave out the in in the IGobbler declaration, it will suggest that you add it - with the suggestion "Make type parameter T contravariant" - allowing a QuadrupedGobbler to be used as an IGobbler<Donkey>.
In general, the same logic outlined above applies in any case where an interface declaration contains a generic parameter that is only used as the type of method parameters, not return types.
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.
Consider the following:
public interface ITree<X>
{
...
ITree<X> Union(ITree<X> other);
...
}
The idea is that I'm going to implement several types of tree. However, the Union() method only works if you try to union two trees of the same type. The type signature above does not enforce this restriction, however.
So, my question is: How can I write a type signature for Union() such that the other argument must have the same type as this?
(Obviously I can do a dynamic run-time test and throw an exception if the types don't match. But I would much, much rather to check this at compile-time if it can be done...)
There isn't a particularly clean way of expressing this, this is a consequence of using interfaces, since there's no way to know the implementing type of ITree<X>. The best method is probably to create another class/interface which constrains the concrete tree type and does the operation(s) you require:
public interface ITreeUnion<T, X> where T : ITree<X>
{
T Union(T left, T right);
}
you'll then have to pass instances of this interface type to where you need to carry out the required operation.
If you really require Union to go on the interface you can use a recurring template:
public interface ITree<T, X> where T : ITree<T, X>
{
T Union(T other);
}
public class RedBlackTree<T> : ITree<RedBlackTree<T>, T>
{
public RedBlackTree<T> Union(RedBlackTree<T> other)
{
}
}
According to your requirment, you would need a generic declaration of Union().
interface
public partial interface ITree<X> {
T Union<T>(T other) where T: ITree<X>;
}
sample classes
public partial class TreeOfObject: ITree<object> {
public T Union<T>(T other) where T: ITree<object> {
return default(T); // sample only; shuold be implemented yourself
}
}
public partial class TreeOfInt: ITree<int> {
public T Union<T>(T other) where T: ITree<int> {
return default(T); // sample only; shuold be implemented yourself
}
}
test
public static partial class TestClass {
public static void TestMethod() {
var x=new TreeOfObject();
var y=new TreeOfInt();
var xx=x.Union(x);
var yy=y.Union(y);
var xy=x.Union(y); // won't compile
var yx=y.Union(x); // won't compile
}
}
Why do you need the interface then? Simply implement a Replace method on each implementation of a tree:
public class RedBlackTree<T> {
public RedBlackTree<T> Union(RedBlackTree<T> other) { ... }
}
public class SplayTree<T> {
public SplayTree<T> Union(SplayTree<T> other) { ... }
}
Since you're looking for compile-time safety when dealing with each implementation of ITree, I would argue you just need to deal with the concrete types. Of course, you could have an ITree<T> with other methods on it if you require.
Somehow, the following actually compiles:
public interface ITree<TSelf, TItem> where TSelf : ITree<TSelf, TItem>
{
TSelf Union(TSelf other);
// ...
}
public class AvlTree<TItem> : ITree<AvlTree<TItem>, TItem> {
public AvlTree<TItem> Union(AvlTree<TItem> other) {
return other;
}
}
Of course it's not particularly useful, since then you'd have to declare variables as ITree<AvlTree>, at which point you might as well not use the interface. With C# generics, the values of generic type parameters have to be known at some point to reify the generic type.
I want to write an extension method for a collection of objects that uses base class as a type requirement. I understand this is not necessarily the best way to do things, but I am curious because I'm interested in learning the nuances of the language. This example explains what I would like to do.
public class Human { public bool IsHappy { get; set; } }
public class Man : Human { public bool IsSurly { get; set; } }
public class Woman : Human { public bool IsAgreeable { get; set; } }
public static class ExtMethods
{
public static void HappinessStatus(this IEnumerable<Human> items)
{
foreach (Human item in items)
{
Console.WriteLine(item.IsHappy.ToString());
}
}
}
// then in some method, I wish to be able to do the following
List<Woman> females = RetreiveListElements(); // returns a list of Women
females.HappinessStatus(); // prints the happiness bool from each item in a collection
The only way I can get the extension method to expose is to create a collection of Humans. Is it possible to call this type of extension method on derived types as long as I only reference members of the base type?
Your code will actually compile as is with the C# 4 compiler, as that version supports contravariant type parameters.
To get it working with C# 3, you can create a generic extension method for IEnumerable<T> with a where T : Human constraint that acts on the generic type, instead of specifically only for IEnumerable<Human>:
public static void HappinessStatus<T>(this IEnumerable<T> items) where T : Human
{
foreach (T item in items)
{
Console.WriteLine(item.IsHappy.ToString());
}
}
Then you can call the extension method on your List<Woman> collection as you describe.