0

This is what I want to do in C# (within class Helper - without generic arguments),

List<AbstractClass<dynamic>> data; public void Add<T>(AbstractClass<T> thing) { this.data.Add((AbstractClass<dynamic>) thing); } 

This helper class would take and work with AbstractClass<> objects and give back AbstractClass<> of specific generic type. AbstractClass<T> contains many functions which return T / take in T like public T Invoke(). For Helper class T cannot be known beforehand. The Add<T>(.. thing) function is not in a class of type T. To be used like this in Helper class's functions,

foreach(var c in data.Where(x => ...)) { // public T Invoke() { ... } function within AbstractClass<T> var b = c.Invoke(); // logic } 

This also fails,

List<AbstractClass<object>> data; public void Add<T>(AbstractClass<T> thing) { this.data.Add((AbstractClass<object>) thing); } 

Now I think I can have,

List<dynamic> data; // or List<object> data; public void Add<T>(AbstractClass<T> thing) { this.data.Add(thing); } 

but I want the constraint that List named data has only elements of type like

ConcreteClass : AbstractClass<OtherClass> 

So we would know that there is an public T Invoke() function but we do not know what it returns. This is helpful to avoid mistakes of say misspelling Invocke and only knowing at run-time.

I want to avoid casting to dynamic every time to invoke functions that give back generic type T

2
  • 8
    Why not declare data as List<AbstractClass<T>> data;? Commented Aug 2, 2013 at 15:45
  • The class which contains the List<..> data is not of type T. The Add<T>(... thing) function must handle adding many different concrete objects which extend the AbstractClass while not knowing what T is. I hope that makes some sense. That is class Helper { ... List<..> data; public void Add<T>(... data) { ... } .. } Commented Aug 2, 2013 at 16:14

2 Answers 2

1

To do what you want to do you are going to need to use a Contravariant interface

public class Program { static void Main() { var m = new Helper(); m.Add(new ConcreteClass()); m.Process(); } class Helper { List<IAbstractClass<OtherClassBase>> data = new List<IAbstractClass<OtherClassBase>>(); public void Add(IAbstractClass<OtherClassBase> thing) { this.data.Add(thing); } public void Process() { foreach(var c in data.Where(x => x.ShouldBeProcessed())) { var b = c.Invoke(); Console.WriteLine(b.Question); var castData = b as OtherClass; if (castData != null) Console.WriteLine(castData.Answer); } } } public interface IAbstractClass<out T> { bool ShouldBeProcessed(); T Invoke(); } abstract class AbstractClass<T> : IAbstractClass<T> { public bool ShouldBeProcessed() { return true; } public abstract T Invoke(); } class ConcreteClass : AbstractClass<OtherClass> { public override OtherClass Invoke() { return new OtherClass(); } } class OtherClassBase { public string Question { get { return "What is the answer to life, universe, and everything?"; } } } class OtherClass : OtherClassBase { public int Answer { get { return 42; } } } } 

You do not need to tell Add what kind of class you are passing it, all that matters is it derives from the type specified. You could do public void Add(IAbstractClass<object> thing) and every class would work, but Invoke() would only return objects inside the foreach loop.

You need to figure out what is the most derived class you want Invoke() to return and that is what you set as the type in the list.

Sign up to request clarification or add additional context in comments.

1 Comment

Except a single instance Helper needs to be able to take in classes which extend AbstractClass<A>, AbtrasctClass<B>, ... AbtrasctClass<Z>
0

Maybe this will work for you:

public class Program { static void Main() { var m1 = new Helper<OtherClass>(); m1.Add(new ConcreteClass()); var m2 = new Helper<int>(); m2.Add(new ConcreteClass2()); } class Helper<T> { List<AbstractClass<T>> data = new List<AbstractClass<T>>(); public void Add<T1>(T1 thing) where T1 : AbstractClass<T> { this.data.Add(thing); } } class AbstractClass<T> { } class OtherClass { } class ConcreteClass : AbstractClass<OtherClass> { } class ConcreteClass2 : AbstractClass<int> { } } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.