Let's say I have the following classes that have different implementations based on the object to be stored in:
public class ListOfPersistent<T> :
IList<T> where T : Persistent {... implementation ...}
public class ListOfNonPersistent<T> :
IList<T> {... implementation ...}
And I want to use one of another version on the above classes by doing something like this:
public class PersistentList<T> : IList<T> {
protected PersistentList() {
if (list != null) {
return;
}
if (Extensions.IsPersistent<T>()) {
list = new ListOfPersistent<T>();
} else {
list = new ListOfNonPersistent<T>();
}
}
protected IList<T> list;
....
}
Of course the above does not compiles, because there is a type constrain on the first class and none on the second. Is there any way I can: Tell the compiler that it should not check the constrain on this specific case (list = new ListOfPersistent<T>()) because I KNOW it will be of that type, or do some covariance/contravariance magic so the code compiles without any issues?
Covariance and contravariance won’t help you here because IList<T> is invariant.
Personally I would argue that you have a flaw in your class design. You shouldn’t want to instantiate a ListOfPersistent<T> and then place it in a variable whose type, IList<T>, is incompatible. Unfortunately I cannot suggest a good alternative because I have no idea how you are planning to use these classes or what your overall goal is; but I can make a suggestion with a disclaimer that it is hacky and should probably only be used if you really know what you are doing:
public static class ListUtils
{
public static object CreateListOfPersistent(Type elementType)
{
if (!typeof(Persistent).IsAssignableFrom(elementType))
throw new ArgumentException("elementType must derive from Persistent.", "elementType");
var listType = typeof(ListOfPersistent<>).MakeGenericType(elementType);
return Activator.CreateInstance(listType);
}
}
// ...
if (Extensions.IsPersistent<T>())
list = (IList<T>) ListUtils.CreateListOfPersistent(typeof(T));
else
list = new ListOfNonPersistent<T>();
Related
I was doing some work with interfaces today, when I run into the following scenario. Given these two simple interfaces:
public interface IItem { }
public interface IInventory
{
ICollection<IItem> Items { get; }
}
I made a simple class to implement IInventory, and noticed that this implementation is perfectly fine as written:
public class BasicInventory1 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return items.Values; }
}
}
But yet, this implementation requires a cast:
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return (ICollection<IItem>)items; }
}
}
Why does one require a cast and the other doesn't? Checking the object typing for both collections that are getting returned in either case confirms that they both in fact implement ICollection.
I suspect there is some magic type conversions going on under the hood here, and therefore seems to have something to do with co/contravariance, but I don't quite see what exactly is going on.
Dictionary<int, IItem> does not implement ICollection<IItem>. Simple as that.
It wouldn't make sense to implement that interface because you cannot add to a dictionary without specifying a key. The interface does not make sense.
This is a runtime error because items could refer to a subclass of Dictionary so that the cast might be valid.
I think that if you were to add .Values to the second example, you would not need the cast
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items;
public ICollection<IItem> Items
{
get { return items.Values; }
}
}
This is because items is a Dictionary and that implements ICollection<KeyValuePair<TKey, TValue>>.
This code is NOT VALID and will always generate a runtime error:
public class BasicInventory2 : IInventory
{
private Dictionary<int, IItem> items = new Dictionary<int, IItem>();
public ICollection<IItem> Items
{
get
{
return (ICollection<IItem>) items;
}
}
}
A Dictionary<int, IItem> does NOT implement ICollection<IItem>, whereas the type returned from Dictionary<int, IItem>.Values does.
So the answer is:
The first case is ok because Values is of the correct type.
In the second case, the compiler knows that you are trying to return the wrong type and so it gives you a compile error.
If you override the error with a case, you will get a runtime BadCastException.
In BasicInventory1 you return items.Values in BasicInventory2 you return only items.
.Values returns a ICollection, so no cast is need.
MSDN:
Dictonary
Values
In the second code you use the dictionary as return value where in the first code you use the values. Dictionary<int,IItems> inherits from ICollection<KeyValuePair<int,IItems>> thus is not ICollection<IItems>. Therefore you need the cast.
I have a series of static methods to modify a collection then return the modified collection:
private static IEnumerable<Invoice> ResolveProxies(IEnumerable<Invoice> e) {
// do something to e
return e;
}
private static IEnumerable<Person> ResolveProxies(IEnumerable<Person> e) {
// do something to e
return e;
}
In another part of the application there is a method to decide if a collection is of a certain type, so that it can be converted to that type and have its corresponding ResolveProxies method called:
public static GridModel<T> ToGridModel<T>(this GridModel gridModel) {
// gridModel.Data is just IEnumerable
var collection = gridModel.Data as IEnumerable<T> ?? new List<T>();
return new GridModel<T> {
Data = EvaluateDynamicProxies(collection),
Total = gridModel.Total
};
}
private static IEnumerable<T> EvaluateProxies<T>(IEnumerable<T> collection) {
if (collection is IEnumerable<Invoice>) {
var enumeration = (collection as IEnumerable<Invoice>);
return ResolveProxies(enumeration) as IEnumerable<T>;
}
if (collection is IEnumerable<Person>) {
var enumeration = (collection as IEnumerable<Person>);
return ResolveProxies(enumeration) as IEnumerable<T>;
}
// proxy resolution isn't needed so return the unchanged collection
return collection;
}
Having such repetitive conditional logic is bad code smell. I'm struggling to come up with some way to mark particular types so that I know they have a corresponding proxy resolver method. Something like this perhaps:
public interface IProxyResolver<out T> where T:IEnumerable<T> {
T ResolveProxies();
}
But how would I use this? In effect I need a way to ask the compiler:
Does T have a matching ResolveProxies method?
What is the name of the class or method that resolves proxies for T so that I can get an instance of it and call it?
You could use an inversion of control (IOC) framework. For example, my team uses Castle Windsor. You can register services (usually interfaces) and types that provide the services. It has some nice generics resolution, so you can do things like this:
interface IProxyResolver<T> { /* whatever */ }
class ProxyResolver<T> : IProxyResolver<T> { /* ... */ }
class PersonProxyResolver : ProxyResolver<Person> { }
class InvoiceProxyResolver : ProxyResolver<Invoice> { }
then, you can summon these types like this:
void SomeMethodThatNeedsAProxyResolver<T>(T obj)
{
var resolver = ioc.Resolve<IProxyResolver<T>>();
//...
}
If you've regsitered the classes above, when T is Person or Invoice, you get the correct non-generic subclass of ProxyResolver; if it is any other type, you get the default generic superclass. Of course, you can structure things differently; if you need a specific proxy resolver for every type, that's possible too.
How about using a custom attribute? This is how custom serializers are selected, etc.
You'd start by defining the Attribute class:
public class ProxyResolverAttribute : Attribute {
public Type ResolverType { get; set; }
public ProxyResolver(Type resolverType) { ResolverType = resolverType; }
}
and then put that on the type contained, e.g.
[ProxyResolver(TypeOf(InvoiceProxyResolver))]
public class Invoice ... { ... }
then use reflection to see if the generic type used in the collection specifies a proxy resolver type:
// Untested, beware of bugs
var enumerationGenericType = enumeration.GetType().GetGenericArguments().FirstOrDefault();
var resolverAttribute = enumerationGenericType.GetType().GetCustomAttributes(TypeOf(ProxyResolverAttribute)).FirstOrDefault();
if (resolverAttribute != null) {
var resolverType = resolverAttribute.ResolverType;
// instanciate something of resolverType here
}
EDIT: Reading the comments, if you don't want to apply the attributes to the contained objects, I'd suggest creating custom classes which inherit List and apply the attribute there, e.g.
[ProxyResolver(TypeOf(InvoiceProxyResolver))]
public class InvoiceList : List<Invoice>
I'm not totally convinced this is possible, but here goes. I have a method returning an object, although the actual type is Collection. Now, I can easily cast the object into the collection using
var myCollection = myObject as Collection<MyClassA>;
However the problem I have is that Collection<MyClassA> could alternatively be Collection<MyClassB> or Collection<MyClassC>. All of these MyClassX's are inherited from MyBaseClass, so ideally I would like to be able to do something like
var myCollection = myObject as Collection<MyBaseClass>;
However this throws an exception when casting. Is it possible to do this in anyway? I understand that it may be within .Net 4?
Thanks for the help.
EDIT:
OK - The answers so far are very useful, however they only solve the second part of the solution - converting/casting collections.
I am still unsure as to how I should initially cast the object to a collection (without the use of a huge if statement for each of the possible types)
This is only supported with IEnumerable<T> in .NET 4. Check out the difference in the signatures:
IEnumerable<T>:
public interface IEnumerable<out T> : IEnumerable
Collection<T>:
public class Collection<T> : IList<T>,
ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
That out keyword in the type parameter is what tells .NET to support variance.
Before I had access to .NET 4 I wrote an extension method that achieved this:
public static IEnumerable<U> CastCollection<T, U>(this IList<T> items) where U : class
{
var collection = new List<U>();
foreach (var item in items)
{
if (item is U)
{
var newItem = item as U;
collection.Add(newItem);
}
}
return collection;
}
You would use it like this:
var myCollection = myObject.CastCollection<MyClassA, MyBaseClass>();
myCollection will be an IEnumerable<MyBaseClass> in this case.
Alternate solution: you could use interfaces and generics to get what you want.
public interface IMyClass
{
}
public class MyClassA : IMyClass
{
}
public class MyClassB : IMyClass
{
}
public class MyClassC : IMyClass
{
}
static void Main(string[] args)
{
var listA = new List<IMyClass>{new MyClassA{}, new MyClassA{}};
var listB = new List<IMyClass> { new MyClassB { }, new MyClassB { } };
var listC = new List<IMyClass> { new MyClassC { }, new MyClassC { } };
List<IMyClass> genericList = listA.Cast<IMyClass>().ToList();
}
Something like this will compile properly and also allow you to assign different lists of any types that implement the common interface, to the same variable (in this case genericList.
This cannot be done by casting the collection as a whole. However, you can cast the individual elements to a new collection. Look at LINQ's Cast<> extension method.
public class ConfigControlBase<T> : UserControl
where T : ProviderBase
{
public T Provider { get; set; }
public void Init(T provider)
{
this.Provider = provider;
}
}
public abstract class ProviderBase
{
public abstract ConfigControlBase<ProviderBase> GetControl();
}
public class ProviderXConfigControl : ConfigControlBase<ProviderX>
{
}
public class ProviderX : ProviderBase
{
public override ConfigControlBase<ProviderBase> GetControl()
{
var confControl = new ProviderXConfigControl() as ConfigControlBase<ProviderX>;
return confControl;
}
}
return confControl; throws an exception:
Cannot implicitly convert type ConfigControlBase<ProviderX> to ConfigControlBase<ProviderBase>
Let's change the name of your classes and properties, but keep the shape the same:
public class Cage<T> where T : Animal
{
public T Contents { get; set; }
}
public class Aquarium : Cage<Fish> { }
public abstract class Animal
{
public abstract Cage<Animal> GetCage();
}
public class Fish : Animal
{
public override Cage<Animal> GetCage()
{
return (Cage<Animal>)(new Aquarium());
}
}
Now is it clear why this is not legal? Suppose it were legal. Then you could do this:
Fish fish = new Fish();
Cage<Animal> cage = fish.GetCage();
cage.contents = new Tiger();
And now you have a tiger in your aquarium. And no one wants that.
The compiler (or runtime) has to prevent this type error somehow; it chooses to prevent it as soon as possible. The earliest it can do so is on the type test for the conversion from Aquarium to Cage<Animal>. The compiler knows that this can eventually lead to tigers in aquariums, so it does not allow the conversion at all. If you force the compiler to allow it through casts then it fails at runtime.
Generic types with assignable type arguments are not assignable themselves.
For instance, you cannot cast List<string> to List<object>, although string is an object.
It is not immediately obvious why such casting is not supported so let me give you an example:
var words = new List<string> { "Serve God", "love me", "mend" };
var objects = (List<object>) words; // C# compiler wouldn't allow this
objects.Add (new Car()); // we just added a Car to Shakespeare's work and the universe exploded
C# doesn't encourage universe explosion, however since C# 4.0 a light version of this idea is implemented. You see, in some cases such casting would actually be safe.
.NET 4.0 brings concepts of covariance and contravariance in generics only for interfaces and delegates, you may want to check this out.
Example (doesn't work prior to .NET 4.0):
void HandleCollection (IEnumerable<object> collection)
{
// ...
}
var words = new List<string> { "Serve God", "love me", "mend" };
// IEnumerable is defined as IEnumerable<out T> in .NET 4.0
// 'out' keyword guarantees that T is only used for return values
// and therefore client code can't explode the universe
var objects = (IEnumerable<object>) words;
HandleCollection (objects);
This is because ConfigControlBase<ProviderX> is not a ConfigControlBase<ProviderBase>
your
public override ConfigControlBase<ProviderBase> GetControl()
doesn't match
var confControl = new ProviderXConfigControl() as ConfigControlBase<ProviderX>;
This answer might not be useful in your scenario, as you should probably look for another solution, but during reflection I found the ability to cast to less generic types very useful, hence I wrote a solution for it. It only works for interfaces however, and you do have to guarantee you will only pass objects of the correct types to the interface.
I basically generate a proxy class at runtime which does all the required casts for you. It's usage looks as follows:
object validator; // An object known to implement IValidation<T>.
object toValidate; // The object which can be validated by using the validator.
// Assume validator is IValidation<string> and toValidate a string.
IValidation<object> validation
= Proxy.CreateGenericInterfaceWrapper<IValidation<object>>( validator );
validation.IsValid( toValidate ); // This works! No need to know about the type.
// The following will throw an InvalidCastException.
//validation.IsValid( 10 );
More information and source code can be found on my blog.
I have class where the relevant part looks like
class C {
void Method<T>(SomeClass<T> obj) {
list.Add(obj);
}
List<?> list = new List<?>();
}
How should I define the list so that the class compiles?
I want a list of type List<SomeClass<?>>, that is a list of objects of SomeClass where each object can have any type parameter. The Java ? construct allows this; what is the C# equivalent? If no such thing exists, is there a suitable workaround? (A List<object> would do but is terribly ugly.)
I don't think you can do this in C#... you would have to add the type parameter to the class:
class C<T> {
void Method(SomeClass<T> obj) {
list.Add(obj);
}
List<SomeClass<T>> list = new List<SomeClass<T>>();
}
The other option would be to use an interface:
class C {
void Method<T>(T obj)
where T : ISomeClass {
list.Add(obj);
}
List<ISomeClass> list = new List<ISomeClass>();
}
To do what you want, you have two options.
You can use List<object>, and handle objects. This will not be typesafe, and will have boxing/unboxing issues for value types, but it will work.
Your other option is to use a generic constraint to limit to a base class or interface, and use a List<Interface>.
Unfortunately, there is no direct equivalent in C# 3.0 as generics are invariant.
You'll be able to do something like this in a graceful manner using C# 4.0 safe co/contra-variance feature.
To workaround it, you could inherit SomeClass<T> from a nongeneric base and create a List<BaseClass> instead.
If each instance of the class should hold only one type, you could make the class itself generic and set the type parameter there.
I don't know anything about Java's ? construct, but I think the following most closely preserves your existing syntax while also matching your description.
class SomeClass<T>
{
}
class C
{
void Add<T>(SomeClass<T> item)
{
Type type = typeof(SomeClass<T>);
if (!list.ContainsKey(type))
list[type] = new List<SomeClass<T>>();
var l = (List<SomeClass<T>>)list[type];
l.Add(item);
}
public void Method<T>(SomeClass<T> obj)
{
Add(obj);
}
readonly Dictionary<Type, object> list = new Dictionary<Type, object>();
}
test it with the following:
class Program
{
static void Main(string[] args)
{
var c = new C();
var sc1 = new SomeClass<int>();
var sc2 = new SomeClass<String>();
c.Method(sc1);
c.Method(sc2);
c.Method(sc1);
c.Method(sc2);
}
}
Personally, I would do this where possible; move the generic parameter from the method, to the class.
class C<T> {
void Method(SomeClass<T> obj) {
list.Add(obj);
}
List<?> list = new List<?>();
}
If your generic list is a member, it stands to reason that the class should be constructed with this in mind. It is hard for us to suggest the best pattern without more usage context for the class.