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.
Related
I have individual methods such as:
public string Method1()
{
class1 c1= new class1 ();
var data = c1.GetMainData(Id);
var value= c1.GetValue(data,c1);
}
public string Method2()
{
class2 c2= new class2 ();
var data = c2.GetMainData(Id);
var value= c2.GetValue(data,c2);
}
public string Method3()
{
class3 c3 = new class3 ();
var data = c3.GetMainData(Id);
var value= c3.GetValue(data,c3);
}
From the above functions, classes class1, class2, and class3 are different but the method names GetMainData and GetValue are same in the class.
method names are same and passing class object to method and have different functionality and returning string.
Please help me to write a generic single method to handle?
Unlike C++, C# has only limited duck typing, and only for compiler internals (disposing) or extension methods. Neither of them apply here.
You have three options here. You either use a common polymorphic base type that allows you to call your methods:
interface I {
object GetMainData(int id);
object GetValue(int data);
}
class class1 : I {
// implement the interface
}
// same for class2 and class3
public string Method<T>() where T: I, new()
{
var c = new T();
var data = c.GetMainData(Id);
var value= c.GetValue(data);
// return something
}
You can also use reflection to call methods by name from unrelated objects.
And of course, you can use dynamic to create a compiler site to do the same for you.
Note that the last two are orders of magnitude slower than the first option, though dynamic's cost is mostly at the first call to build the site and compile the new generated code, subsequent calls are pretty fast.
have you tried writing a generic method?
interface IMyInterface
{
string GetMainData(string id);
string GetValue(string data);
}
string getValue<T>() where T:IMyInterface,new()
{
var c = new T();
var data = c.GetMainData(Id);
return c.GetValue(data);
}
the where clause indicates the minimum requirements of T, in this case any class passed as T must inherit from IMyInterface and have a empty constructor, because of this the compiler knows that T must have a new() and all methods and properties specified on the IMyInterface interface
additional note: if you are using an interface then the generics are probably not even required as you can call the instance functions with out knowing exactly what class they are
string getValue(IMyInterface c)
{
var data = c.GetMainData(Id);
return c.GetValue(data);
}
the generics is generally only required when you need the return or inputs to be the same type as T
the most common generic i write is a collection extentions
public static Add(this ICollection<T> col, IEnumerable<T> items)
{
foreach(var item in items)
col.Add(item)
}
here if the items are not the same type as the collection then the code doesn't work, however we actually don't care what type the items and collection are as long as they match
Can someone please explain why this code snippet is not working? Why is a not castable to b?
I was thinking about covariance and contravariance but as far as I'm concerted this is not applicable to abstract classes.
Compile Error:
Cannot convert type 'ConsoleApplication1.SVM' to 'ConsoleApplication1.VMSBase' ConsoleApplication1\Program.cs
class Program
{
static void Main(string[] args)
{
var a = new SVM();
var b = (VMSBase<Model>)a;
}
}
class SVM : VMSBase<SpecialModel>
{
}
class VMSBase<TS> : VMBase<TS> where TS : Model
{
}
class VMBase<T> where T : Model
{
}
class SpecialModel : Model
{
}
class Model
{
}
SVM is a subtype of VMSBase<SpecialModel>, so it can be converted to one.
But there's no polymorphic relationship between VMSBase<SpecialModel> and VMSBase<Model>, because the generic type parameter T in VMSBase<T> is invariant.
In order for VMSBase<X> to be a subtype of VMSBase<Y> (where X is a subtype of Y), T has to be covariant. You mark it as covariant using the out keyword: VMSBase<out T>. This, however, forces you to use the type T only for return values from all members (methods, properties, etc) and never as an input value (method arguments).
There's another catch: c# only allows variance on interfaces. So you'll have to change both VMBase and VMSBase to be interfaces.
class Program
{
static void Main(string[] args)
{
SVM a = new SVM();
var b = a as IVMSBase<Model>;
}
}
class SVM : IVMSBase<SpecialModel> {}
interface IVMSBase<out TS> : IVMBase<TS> where TS : Model {}
interface IVMBase<out T> where T : Model {}
More info: Covariance and Contravariance FAQ
Bottom line is that VMSBase<SpecialModel> is not the same as VMSBase<Model>.
This is the same reason why this won't compile:
List<ViewBase> list = new List<GridView>();
Although GridView inherits from ViewBase.
It's just how the language works, a limitation of generics you might say.
Imagine you could legally do the cast. Now imagine we have this method defined that eats models:
class VMSBase<TS> : VMBase<TS> where TS : Model
{
public void GobbleUpModel(TS model)
{
}
}
Using this, we can now bypass type-safety in the following (surprising if you haven't seen it before) manner:
//SpecialModel2 is some other subclass of Model, not related to SpecialModel
SpecialModel2 incompatibleModel;
var a = new VMSBase<SpecialModel>();
var b = (VMSBase<Model>)a;
//forces a to gobble up a model that is incompatible with SpecialModel
b.GobbleUpModel(incompatibleModel);
The reason why generics are not variant in C# is because it could cause typing problems: using your example, assume that VMSBase has a property of type T named MyProperty. If the casting was possible, you would be able to do something like:
var a = new VMSBase<SpecialModel>();
var b = (VMSBase<Model>) a;
b.MyProperty = new Model();
Now you just set the value of b.MyProperty to an instance of a Model; but that is not consistent with the type expected in VMSBase, which is actually SpecialModel.
I have a generic type Store<T> and use Activator to make an instance of this type. Now how, after using the Activator, can I cast the resulted object of type object back to the instantiated type? I know the type that I used to instantiate the generic. Please see the following code:
class Store<T> where T : IStorable
{}
class Beer : IStorable
{}
class BeerStore : Store<Beer>
{}
Type storeType = someObjectThatImplementsIStorable.GetType();
Type classType = typeof(Store<>);
Type[] typeParams = new Type[] { storeType };
Type constructedType = classType.MakeGenericType(typeParams);
object x = Activator.CreateInstance(constructedType, new object[] { someParameter });
What I would like to do is something like this:
var store = (Store<typeof(objectThatImplementsIStorable)>)x;
but that doesn't work for obvious reasons. As an alternative I tried:
var store = (Store<IStorable>)x;
which could possibly work in my opinion, but gives an InvalidCastException.
How do I get access again to the Store<T> methods that I know are in the object x?
Since the actual type T is available to you only through reflection, you would need to access methods of Store<T> through reflection as well:
Type constructedType = classType.MakeGenericType(typeParams);
object x = Activator.CreateInstance(constructedType, new object[] { someParameter });
var method = constructedType.GetMethod("MyMethodTakingT");
var res = method.Invoke(x, new object[] {someObjectThatImplementsStorable});
EDIT You could also define an additional IStore interface that does not use generics, and uses IStorable instead:
interface IStore {
int CountItems(IStorable item);
}
class Store<T> : IStore where T : IStorable {
int CountItems(IStorable item) {
return count;
}
}
Your Store<T> would remain generic, but you would get access to its CountItems by casting to IStore:
var x = (IStore)Activator.CreateInstance(constructedType, new object[] { someParameter });
var count = x.CountItems((IStorable)someObjectThatImplementsStorable);
Cant you just wrap it?
something like
public Store<T> IConstructStore<T>(T item) where T : IStorable
{
return Activator.CreateInstance(typeof(Store<T>), new object[] { someParameter }) as Store<T>;
}
or am i missing what you are trying to do?
IE
class Program
{
static void Main(string[] args)
{
Beer b = new Beer();
var beerStore = IConstructStore(b);
Console.WriteLine(beerStore.test);
Console.WriteLine(beerStore.GetType().ToString());
}
public static Store<T> IConstructStore<T>(T item) where T : IStorable
{
return Activator.CreateInstance(typeof(Store<T>), new object[] { }) as Store<T>;
}
}
interface IStorable { }
class Store<T> where T : IStorable
{
public int test = 1;
}
class Beer : IStorable
{ }
prints
1
ConsoleApp1.Store'1[ConsoleApp1.Beer]
Most appropriate answer in my opinion would be 'you can't do it in this way'.
You might try introducing an interface IStorage and try making it covariant or contravariant (have you seen that option?). If it is not an option, for example if you have both input and output generic types used in Storage, then there is no way to implement what you want. The reason is that Storage<Beer> cannot be safely used as Storage<IStorable> due to this case:
Storage<IStorable> store = new Storage<Beer>(); // let's pretend we can do it
store.Save(new StorableButNotBeer()); // what will happen here?
The only possible workaround for you as I see is to move casting out from this method and cast the object in the place where you know all the exact types:
public void object CreateStore(Type istorableType)
{
// here is your activator code, but you will have to return an object
}
var beerStore = (Store<Beer>)CreateStore(typeof(Beer));
T must be the type Store<X> avoiding the use of typeof(Store<T>
Let's say that someObjectThatImplementsIStorable is of type MyStorable.
e.g.
MyStorable someObjectThatImplementsIStorable = new MyStorable( );
... // rest of your code here.
Then x cannot be cast to Store, but it can be cast to Store. The following will work: (Store)x
Note that although MyStorable implements IStorable, there is no relationship between Store and Store. These are two distinct classes that do not derive from each other.
u.
If I would like to write a method that takes a variable number of "TDerived" where TDerived is any subclass of a class "Base", is there any way to do this?
The following code only works with a single specific specified subclass:
void doStuff<TDerived>(params TDerived[] args) where TDerived : Base
{
//stuff
}
ie if I have
class Super { }
class Sub0 : Super { }
class Sub1 : Super { }
then I cannot do
Sub0 s0 = new Sub0();
Sub1 s1 = new Sub1();
doStuff(s0, s1);
since I get "best overloaded match... has some invalid arguments".
Regardless of how the compiler handles the type constraints and variadic functions, this seems (as far as I can tell) completely type-safe. I know I could cast, but if this is type safe why not allow it?
EDIT:
Perhaps a more convincing example:
void doStuff<TDerived>(params SomeReadOnlyCollection<TDerived>[] args) where TDerived : Base
{
foreach(var list in args)
{
foreach(TDerived thing in list)
{
//stuff
}
}
}
TDerived needs to be able to resolve to a single type. In your example, the only type it could resolve to would be Super, but the compiler is not going to make that leap. You can make that leap for the compiler.
doStuff(new Super[] { s0, s1 });
doStuff<Super>(s0, s1);
Regarding your update, consider (instead of a generic method) defining a method accepting IEnumerable<ISuper>, which will support derived types because IEnumerable<T> is covariant (as of .NET 4). IEnumerable<T> is also inherently readonly and forward-only, perfect if you have a foreach loop. Full working example:
class Program
{
static void Main()
{
var sub0s = new Sub0[] { new Sub0() };
var sub1s = new List<Sub1> { new Sub1() };
doStuff(sub0s, sub1s);
}
static void doStuff(params IEnumerable<ISuper>[] args)
{
foreach (var sequence in args)
{
foreach (var obj in sequence)
{
Console.WriteLine(obj.GetType());
// you have the ability to invoke any method or access
// any property defined on ISuper
}
}
}
}
interface ISuper { }
class Super : ISuper { }
class Sub0 : Super { }
class Sub1 : Super { }
IEnumerable<T> is implemented by BCL collections since .NET 2.0, including T[], List<T>, ReadOnlyCollection<T>, HashSet<T>, etc.
In your example, you are actually telling the compiler that all arguments to doStuff must be of the same type at compile time, and that this type has to be inherited from Base. If you want to allow the arguments to be of different types, then just don't use generics:
void doStuff(params Base[] args)
{}
EDIT
The same applies with your new example - instead of a specific SomeReadOnlyCollection you can use IEnumerable, as it is covariant:
void doStuff(params IEnumerable<Base>[] args)
{
foreach (var list in args)
{
foreach (var thing in list)
{
}
}
}
Well you could most certainly change
Sub0 s0 = new Sub0();
Sub1 s1 = new Sub1();
To
Super s0 = new Sub0();
Super s1 = new Sub1();
and then it would work if Super is TDerived.
I may be misunderstanding you, but the only way to make a method take any subclass of a base class is to declare the method to take a reference to the base type.
One other alternative you could use is to simply specify the generic parameter explicitly. For example:
var s0 = new Sub0();
var s1 = new Sub1();
doStuff<Super>(s0, s1);
You should be able to apply the same principle on the case with SomeReadOnlyCollection, as long as it is covariant. For example, IEnumerable is such a collection:
static void doStuff2<TDerived>(params IEnumerable<TDerived>[] args) where TDerived : Super {
// ...
}
// ...
var l0 = new List<Sub0>();
var l1 = new List<Sub1>();
doStuff2<Super>(l0, l1);
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>();