You can box and unbox types like this:
List<object> items = new List<object>();
items.Add("hello");
items.Add(123);
Here, it doesn't matter what we put in, as long as it derives from object. So this works.
But is it possible to do it with generic classes?
Like this:
public class Foo<T>
{
public T MyItem;
}
static void Main()
{
List<Foo<object>> items = new List<Foo<object>>();
items.Add(new Foo<string>() { MyItem = "Hello" });
items.Add(new Foo<int>() { MyItem = 123 });
}
Here, it will give me an error despite string and int is type of object.
There is one easy solution that i have thought about, and that is by turning new Foo< string > into new Foo< object >, and then just put in string value in the object type like this:
items.Add(new Foo<object>() { MyItem = "Hello" });
But i'm in a situation where i cant do that.
So is there any solution to make this possible?
To attempt to make your code compile:
You would have to make the parameter T covariant which can only be done on interfaces and delegates. The other limiting factor when defining T as covariant is that T cannot be a value type.
Documentation - out (Generic Modifier) (C# Reference)
For generic type parameters, the out keyword specifies that the type parameter is covariant. You can use the out keyword in generic interfaces and delegates.
... Covariance and contravariance are supported for reference types, but they are not supported for value types.
The question about boxing/unboxing also does not apply in this situation with generics. Generics ensure there never is boxing or unboxing (by default) on the type parameters. There are plenty of good links in the comments, I recommend you read through them so you have a better understanding of 1) boxing/unboxing and 2) generics.
This is the closest you can get with your code
static void Main() {
List<IFoo<object>> items = new List<IFoo<object>>();
items.Add(new Foo<string>() { MyItem = "Hello" });
// not possible because int is a value type
// items.Add(new Foo<int>() { MyItem = 123 });
}
interface IFoo<out T>
{
T MyItem {get;}
}
class Foo<T> : IFoo<T>
{
public T MyItem {get;set;}
}
Given this class:
public class Foo<T>
{
public T MyItem { get; set; }
}
If you have a list of Foo<object> you can't add a Foo<int> to it.
If you could, then you could do this:
var myListOfFoos = new List<Foo<object>>();
myListOfFoos.Add(new Foo<int>());
Foo<object> firstFoo = myListOfFoos[0]; // this is the Foo<int> you added.
firstFoo.MyItem = "string!"; // How can you do this with a Foo<int>?
My eyes always glaze over from the words "covariant" and "contravariant." The compiler is always protecting you from a scenario like this. You just have to figure out what it's (correctly) protecting you from trying to do.
Related
I'd like to instantiate instances of a generic type and pass them around as if they were generic objects of an interface that they implement, such as below. Clearly, this is not allowed. Why is this, and what is the general practice for handling such situations? thanks.
public class MyType<T> where T : IComparable { }
MyType<IComparable> things = new MyType<Int32>();
this gets error:
Cannot implicitly convert type MyType<Int32> to MyType<IComparable>
I want to do this because I need different types of things that I want to pass around to more generic methods such as
public void DoSomething(MyType<IComparable> things) {...}
The assignment compatibility of generic type arguments does not make the generic type itself assignment compatible. This is why: Let's assume that we declared the generic class like this:
public class MyType<T> where T : IComparable
{
public T Value { get; set; }
}
And let's assume that this would compile ...
var intObject = new MyType<int> { Value = 42 };
MyType<IComparable> things = intObject; // Does not compile!
... then we could write
// things.Value has the static type IComparable
things.Value = "hello"; // Allowed because string is IComparable
But this is not possible since the underlying object is a MyType<int> and thus its Value property has the type int. Therefore, we are not allowed to substitute a MyType<int> for a MyType<IComparable>.
I have the follwoing:
subObject, superObject where subObject is a subclass of superObject.
I can always upcast subObject to superObject, but i cannot do the following:
wrapperObject<superObject> instance = (wrapperObject<superObject>) wrraperObject<subObject> instance2;
This is an example with generic lists:
List<Object> l1 = null;
List<Boolean> l2 = null;
l1 = (Object)l2; <<< This will not work
Object o1 = null;
Boolean o2 = false;
o1 = (Object)o2; <<< This works
I understand that in case with lists I can just iterate thru all the objects within the list and typecast them individually.
But this will not work in case of my custom class "wrapperObject"
wrapperObject<superObject> l1;
wrapperObject<subObject> l2;
l1 = (wrapperObject<superObject>)l2; <<< this doesnt work
superObject a = null;
subObject n = null;
a = (superObject)n; <<< this works
Let us assume for a moment that this would be possible
List<bool> lb = new List<bool>();
List<object> lo = (List<object>)lb;
Now, we could do
lo.Add(123); // Since lo is typed as List<object>
but lo is just a reference pointing to List<Boolean> lb. Bang!
A workaround for this type of problem is to have a base type (class or interface) that is not generic and derive a generic one from it. For instance, List<T> implements ICollection<T> which implements IEnumerable<T> which implements IEnumerable. I.e., this assignment is valid:
IEnumerable e = new List<bool>();
Note that you can do this type of conversion with arrays. I.e., you can assign
object[] obj = new Person[10];
The price we must pay for this is efficiency, since a type test is performed when we assign an array element. This type test can throw an exception if we assign a non-compatible value. See: Eric Lippert's Blog on Array Covariance
Oliver's answer is totally right, it explains why you simply can not do this. But I can think of an instructive workaround that besides helping you to achive what you want, it will help you to better understand Covariance and Contravariance in .Net. Consider the following classes:
class SuperObject { }
class SubObject : SuperObject { }
class WrapperObject<T>:IContravariantInterface<T>,ICovariantInterface<T> where T : SuperObject
{
public void DoSomeWork(T obj)
{
//todo
}
public T GetSomeData()
{
//todo
return default;
}
}
We make Wrapper implementing two interfaces: IContravariantInterface<T> and ICovariantInterface<T>. Here are they:
interface IContravariantInterface<in T> where T : SuperObject
{
void DoSomeWork(T obj);
}
interface ICovariantInterface<out T> where T : SuperObject
{
T GetSomeData();
}
By doing this we split up Wrapper functionality into two parts: a covariant one and a contravariant. Why doing this? Because by doing this we can safetly cast either from most derive classes to less ones or the other way around with the condition that we are using the right interface:
var superObjectWrapper = new WrapperObject<SuperObject>();
var subObjectWrapper = new WrapperObject<SubObject>();
ICovariantInterface<SuperObject> covariantSuperObjWrapper = subObjectWrapper;
IContravariantInterface<SuperObject> contravariantSuperObjWrapper = subObjectWrapper; //does not compile
ICovariantInterface<SubObject> covariantSubObjWrapper = superObjectWrapper; //does not compile
IContravariantInterface<SubObject> contravariantSubObjWrapper = superObjectWrapper;
By casting to these interfaces you are sure that you can only access those methods that are safe to use regarding your casting
EDIT
Base on OP's comment below consider writing converter logic in your Wrapper class. Take a look to the following refactored WrapperObject:
class WrapperObject<T> where T : SuperObject
{
private T _justATestField;
public void Copy<TType>(WrapperObject<TType> wrapper) where TType : SuperObject
{
if (wrapper._justATestField is T tField)
{
_justATestField = tField;
}
}
public WrapperObject<SuperObject> GetBaseWrapper()
{
var baseWrapper = new WrapperObject<SuperObject>();
baseWrapper.Copy(this);
return baseWrapper;
}
}
Now you can do:
var subObjectWrapper = new WrapperObject<SubObject>();
WrapperObject<SuperObject> superObjectWrapper = subObjectWrapper.GetBaseWrapper();
What you're asking about are Variant Generics. Right now, C# only allows Variant Generics on Interfaces and only in one direction. The two types of generic variance are covariance where the output of a function can be more precise than the declared variant type or contravariance where the input of a function can be less precise than the declared variant type.
If your interface needs to do both on the same variable, you're out of luck.
I have a little problem for you guys.
I would like to do this:
Type[] classes = new Type[]{ Class1, Class2 };
foreach(Type t in classes){
List<t> list = new List<t>();
}
Is there some way to do this?
You cannot cast to a generic type at runtime, because the type in the generic needs to be resolved at compile time.
You can create a generic type in a dynamic manner using reflection, but unless you hard-code the cast, all you get in return is an object.
I cannot really tell what it is you want, I have to agree with a comment this is an XY problem. I would be inclined to make the presumptuous statement that there is a design issue somewhere that this is trying to solve, instead of addressing the design issue directly, or asking the question of what you are trying to achieve directly.
You can use the following code to create the type, then the dynamic type can be used to duck type the various members of List<T> without knowing/caring that it is a list or what T is:
using System;
using System.Collections.Generic;
namespace ConsoleApplication61
{
class Program
{
static void Main(string[] args)
{
dynamic o = CreateGeneric(typeof(List<>), typeof(int));
o.Add(1);
Console.WriteLine(o[0]);
Console.Read();
}
public static object CreateGeneric(Type generic, Type innerType, params object[] args)
{
System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
return Activator.CreateInstance(specificType, args);
}
}
}
The above sample duck types the Add method and the Indexer. The DLR does the type handling and the duck typing at runtime - knowing that 1 is an int, for example.
Just to clarify, I likely wouldn't use such code in production (unless you requirements are very specific to need this) and any issues with type-mismatching will occur at run time; so you either need to type very accurately (limited IntelliSense) or have good error handling.
Thanks to this blog post for the CreateGeneric method.
This assumes .NET 4 with the new CLR. As #MartinLiversage has also pointed out, this particular sample assumes that you are utilising the list in a sort-of-strongly-typed manner. In my example I am passing an int to a List<int> hidden in a dynamic.
We have been on .NET 4 almost since it was released. We have a large application with an even larger code base. dynamic isn't used once in the application, and only a few times in the test code base. That isn't to say "don't use it", it's to say "most of the time, you don't need it".
You can do it like this:
foreach(Type t in classes)
{
var listType = typeof(List<>).MakeGenericType(t);
var instance = Activator.CreateInstance(listType);
}
This is possible with the Type.MakeGenericType Method
Here's a nifty method I found that should work for ya: CodeRef
public static object CreateGeneric(Type generic, Type innerType, params object[] args)
{
System.Type specificType = generic.MakeGenericType(new System.Type[] { innerType });
return Activator.CreateInstance(specificType, args);
}
And use it like so:
var o = CreateGeneric(typeof(List<>), t);
Unfortunately, to add items you'll have to do it like so (where item is the item you're adding).
MethodInfo addMethod = o.GetType().GetMethod("Add");
addMethod.Invoke(o, new object[] { item.ToType(t) });
Or use the Generic type as mentioned in another answer.
You can try this:
Type[] classes = new Type[] { typeof(A), typeof(B) };
foreach (Type t in classes)
{
Type genericType = typeof(List<>).MakeGenericType(t);
var list = Activator.CreateInstance(genericType);
}
If you want to keep to objects in one list then probably they have something in common.
In such case, I would argue that, just like L.B mentioned in a comment, you are asking a wrong question here.
Probably it's a design issuethat you have. Think about those types, see what they have in common and think about deriving from one base type or make both implement the same interface. In such case you would be able to instantiate a list of the objects of the base type/interface and work with those.
Just to give you a head start:
abstract class Vehicle {
public int NumberOfWheels { get; set; }
}
class Car : Vehicle
{
public Car()
{
NumberOfWheels = 4;
}
}
class Bicycle : Vehicle
{
public Bicycle()
{
NumberOfWheels = 2;
}
}
static void Main(string[] args)
{
var v1 = new Car();
var v2 = new Bicycle();
var list = new List<Vehicle>();
list.Add(v1);
list.Add(v2);
foreach (var v in list)
{
Console.WriteLine(v.NumberOfWheels);
}
Console.ReadKey();
}
I am wondering if it is possible to use the type of one variable to set as the type of another generic variable?
For example, say I have this code:
public class Foo: IBar<ushort>
{
public FooBar()
{
Value = 0;
}
public ushort Value { get; private set; }
}
I also have this class:
public class FooDTO<TType> : IBar<TType>
{
public TType Value { get; private set; }
}
In these examples, in the interface for IBar has the property
TType Value;
Then in my code I have this
var myFoo = new Foo();
var fooDataType = myFoo.Value.GetType();
//I know this line of code does not compile, but this is what I am looking to be able to do
var myFooDTO= new FooDTO<fooDataType>();
Is what I am looking for possible? Would it be too slow for high use code (because of using reflection.
You can do this via Reflection, by using Type.MakeGenericType.
This will have some overhead due to reflection, so you'd need to profile it to see if that will be an issue for you.
Why not use Method type inference:
public class FooDTO<TType> {
public TType Value { get; private set; }
}
public class Foo : FooDTO<ushort> { }
static FooDTO<T> GetTypedFoo<T>(T Obj) {
return new FooDTO<T>();
}
static void Main(string[] args) {
Foo F = new Foo();
var fooDTO = GetTypedFoo(F.Value);
}
Always when I read "generic" and "runtime" in one sentence, I always thing "bad design" or "doesnt understant what generic means". Possibly both.
Generic parameter is integral part of the type. So saying "Generate Generic Type At Runtime" is same as "Generate Foo class at runtime". You are either looking for reflection or change design of your algorithm.
Also var keyword is not going to help you in this case. Forget about it.
You're looking for compile-time reflection, a feature that C# doesn't have. So if you're looking for performance optimizations, the solutions are worse than the problem.
D does have this feature, though; you can easily write
int x = 0;
typeof(x) y = x + 2;
or even much more complicated expressions in D, and it's all evaluated at compile-time.
The core of what you want is:
var type = typeof(FooDTO<>).MakeGenericType(fooDataType);
object obj = Activator.CreateInstance(type);
however, you'll notice that this is reflection, and pretty much ties you to object. The usual workaround to this is to have access to a non-generic version of the API, so that you can work with object - for example (with the addition of a non-generic IBar):
IBar bar = (IBar)Activator.CreateInstance(type);
You can of course move the runtime/generics hit higher up - perhaps into a generic method; then everything in the generic method can use T, and you can use MakeGenericMethod to execute that method in the context of a particular T known only at runtime.
I was under the impression that the C# compiler will implicitly type an array based off a type that they can all be implicitly converted to.
The compiler generates
No best type found for implicitly-typed array
public interface ISomething {}
public interface ISomething2 {}
public interface ISomething3 {}
public class Foo : ISomething { }
public class Bar : ISomething, ISomething2 { }
public class Car : ISomething, ISomething3 { }
void Main()
{
var obj1 = new Foo();
var obj2 = new Bar();
var obj3 = new Car();
var objects= new [] { obj1, obj2, obj3 };
}
I know that the way to correct this is to declare the type like:
new ISomething [] { obj1, ...}
But I'm after an under the covers type help here.
The C# compiler considers the set of types of all the specified elements. It does not consider common base types etc.
You could cast one of the expressions:
var objects= new [] { obj1, obj2, (ISomething) obj3 };
... but personally I'd just use the explicit form:
var objects= new ISomething[] { obj1, obj2, obj3 };
Alternatively, if you explicitly declared any or all of obj1, obj2 and obj3 as type ISomething, that would work fine too without changing the array initialization expression.
From the C# 3 spec, section 7.5.10.4:
An array creation expression of the
third form is referred to as an
implicitly typed array creation
expression. It is similar to the
second form, except that the element
type of the array is not explicitly
given, but determined as the best
common type (§7.4.2.13) of the set of
expressions in the array initializer.
Section 7.4.2.13 looks like this:
In some cases, a common type needs to
be inferred for a set of expressions.
In particular, the element types of
implicitly typed arrays and the return
types of anonymous functions with
block bodies are found in this way.
Intuitively, given a set of
expressions E1…Em this inference
should be equivalent to calling a
method
Tr M<X>(X x1 … X xm)
with the Ei as arguments. More
precisely, the inference starts out
with an unfixed type variable X.
Output type inferences are then made
from each Ei with type X. Finally, X
is fixed and the resulting type S is
the resulting common type for the
expressions.
If the instances can all be cast to the type of any one instance, than that type will be used. It's not enough for all instances to have any type in common, or else the implicity array initialization would always succeed and often generate undesired new object[] arrays.
As a slight addition to the Skeet's reply:
You can either cast one of the array items to the type you need (interface in this case) or if you had just a single element of that type (not deriving but of a direct type). Such as
public static IWindsorInstaller[] MobileRestComponentInstallers
{
get
{
return new []
{
new RepositoryInstaller(),
new AppSettingsInstaller(),
// tens of other installers...
GetLoggerInstaller() // public IWindsorInstaller GetLoggerInstaller()...
};
}
}
this will work, but pls don't do that :) Just define the array type and change the new[] to new IWindsorinstaller[].
It's much more readable having the array type defined explicitly.
Do like this for Class object( UIViewController) initialization in var array:
var page1 = new Class1();
var page2 = new Class2();
var pages = new UIViewController[] { page1, page2 };
Note: here UIViewController can be any class