I am trying to store a collection of generic Foo<T>
elements, where T
may be different for each item. I also have functions like DoSomething<T>(Foo<T>)
that can accept a Foo<T>
of any T
. It seems like I should be able to call this function on each element of the abovementioned list, because they are all valid parameters for the function, but I can't seem to express this idea to the C# compiler.
The problem, as far as I can tell, is that I can't really express a list like that, because C# does not allow me to write Foo<T>
without binding T
. What I would want is something like Java's wildcard mechanism (Foo<?>
). Here is how it might look in a Pseudo-C#, where this wildcard type existed:
class Foo<T> {
// ...
}
static class Functions {
public static void DoSomething<T>(Foo<T> foo) {
// ...
}
public static void DoSomething(List<Foo<?>> list) {
foreach(Foo<?> item in list)
DoSomething(item);
}
}
This pattern is valid in Java, but how can I do the same in C#? I have experimented a bit to find solutions which I'll post in an answer below, but I feel that there should be a better way.
Note: I have already solved this problem "well enough" for my practical needs, and I know ways to work around it (e.g. using the dynamic
type), but I'd really like to see if there is a simpler solution that does not abandon static type safety.
Just using object
or a nongeneric supertype, as has been suggested below, does not allow me to call functions that require a Foo<T>
. However, this can be sensible even if I don't know anything about T
. For example, I could use the Foo<T>
to retrieve a List<T> list
from somewhere, and a T value
from somewhere else, and then call list.Add(value)
and the compiler will know that all the types work out right.
I was asked why I would ever need something like this, so I'm making up an example that is a bit closer to the everyday experience of most developers. Imagine that you are writing a bunch of UI components which allow the user to manipulate values of a certain type:
public interface IUiComponent<T> {
T Value { get; set; }
}
public class TextBox : IUiComponent<string> {
public string Value { get; set; }
}
public class DatePicker : IUiComponent<DateTime> {
public DateTime Value { get; set; }
}
Apart from the Value property, the components will have have many other members of course (e.g. OnChange
events).
Now let's add an undo system. We shouldn't have to modify the UI elements themselves for this, because we have access to all the relevant data already--Just hook up the OnChange
events and whenever the user changes a UI component, we store away the value of each IUiComponent<T>
(A bit wasteful, but let's keep things simple). To store the values we will use a Stack<T>
for each IUiComponent<T>
in our form. Those lists are accessed by using the IUiComponent<T>
as key. I'll leave out the details of how the lists are stored (If you think this matters I'll provide an implementation).
public class UndoEnabledForm {
public Stack<T> GetUndoStack<T>(IUiComponent<T> component) {
// Implementation left as an exercise to the reader :P
}
// Undo for ONE element. Note that this works and is typesafe,
// even though we don't know anything about T...
private void Undo<T>(IUiComponent<T> component) {
component.Value = GetHistory(component).Pop();
}
// ...but how do we implement undoing ALL components?
// Using Pseudo-C# once more:
public void Undo(List<IUiComponent<?>> components) {
foreach(IUiComponent<?> component in components)
Undo(component);
}
}
We could undo everything by directly calling Undo<T>()
on all the IUiComponent
s (by name):
public void Undo(List<IUiComponent<?>> components) {
Undo(m_TextBox);
Undo(m_DatePicker);
// ...
}
However, I want to avoid this, because it means you will have to touch one more place in the code if you add/remove a component. If you have tens of fields and more functions that you want to perform on all the components (e.g. write all their values to a database and retrieve them again), this can become a lot of duplication.
Here is a small piece of code that you can use to develop/check a solution. The task is to put several Pair<T>
-objects into some kind of collection object, and then call a function which accepts this collection object and swaps the First
and Second
field of each Pair<T>
(using Application.Swap()
). Ideally, you should not use any casts or reflection. Bonus points if you can manage to do it without modifying the Pair<T>
-class in any way :)
class Pair<T> {
public T First, Second;
public override string ToString() {
return String.Format("({0},{1})", First, Second);
}
}
static class Application {
static void Swap<T>(Pair<T> pair) {
T temp = pair.First;
pair.First = pair.Second;
pair.Second = temp;
}
static void Main() {
Pair<int> pair1 = new Pair<int> { First = 1, Second = 2 };
Pair<string> pair2 = new Pair<string> { First = "first", Second = "second" };
// imagine more pairs here
// Silly solution
Swap(pair1);
Swap(pair2);
// Check result
Console.WriteLine(pair1);
Console.WriteLine(pair2);
Console.ReadLine();
}
}
For those who may still find this interesting, here is the best solution I could come up with that also meets the "bonus requirement" of not touching the original type in any way. It is basically a Visitor pattern with the twist that we don't store the Foo<T>
directly in our container, but rather store a delegate which calls an IFooVisitor
on our Foo<T>
. Notice how we can easily make a list of those because T
is not actually part of the delegates' type.
// The original type, unmodified
class Pair<T> {
public T First, Second;
}
// Interface for any Action on a Pair<T>
interface IPairVisitor {
void Visit<T>(Pair<T> pair);
}
class PairSwapVisitor : IPairVisitor {
public void Visit<T>(Pair<T> pair) {
Application.Swap(pair);
}
}
class PairPrintVisitor : IPairVisitor {
public void Visit<T>(Pair<T> pair) {
Console.WriteLine("Pair<{0}>: ({1},{2})", typeof(T), pair.First, pair.Second);
}
}
// General interface for a container that follows the Visitor pattern
interface IVisitableContainer<T> {
void Accept(T visitor);
}
// The implementation of our Pair-Container
class VisitablePairList : IVisitableContainer<IPairVisitor> {
private List<Action<IPairVisitor>> m_visitables = new List<Action<IPairVisitor>>();
public void Add<T>(Pair<T> pair) {
m_visitables.Add(visitor => visitor.Visit(pair));
}
public void Accept(IPairVisitor visitor) {
foreach (Action<IPairVisitor> visitable in m_visitables)
visitable(visitor);
}
}
static class Application {
public static void Swap<T>(Pair<T> pair) {
T temp = pair.First;
pair.First = pair.Second;
pair.Second = temp;
}
static void Main() {
VisitablePairList list = new VisitablePairList();
list.Add(new Pair<int> { First = 1, Second = 2 });
list.Add(new Pair<string> { First = "first", Second = "second" });
list.Accept(new PairSwapVisitor());
list.Accept(new PairPrintVisitor());
Console.ReadLine();
}
}
Output:
Pair<System.Int32>: (2,1)
Pair<System.String>: (second,first)