Function specialization in generic class c# - c#

I have a class called PointValue, PointValue and his inheritors can be created only by parametrized constructor that receives one float parameter.
I have a generic class that represents a list of points, template type must inherit from PointValue.
I need that one of the functions would have the ability to add points to the list, because I can't enforce using templates a parametrized constructor. my function gets a pointValueCreator to create the new point.
public class PointList<PointValueT> where PointValueT : PointValue
{
public void addPointToList(float f, Func<float,PointValueT> pointValueCreator)
{
// do something to f and then add a new point:
mylist.Add(pointValueCreator(f));
}
}
So now if I have something like this:
PointList<PointValue> bla = new PointList<PointValue>();
I can call my function like this:
bla.addPointToList(f, (myfloat) => new PointValue(myfloat));
My question is how can I create specialization for addPointToList for my PointValue inheritors, to avoid passing creators.
something like:
public void addPointToList(float f)
{
this.addPointToList(f, (myfloat) => new PointValue(myfloat));
}
I've tried to do it, but the compiler says:
Cannot implicitly convert type 'PointValue' to 'PointValueT'. An explicit conversion exists (are you missing a cast?)
I understand that c# doesn't have specialization, if that is the case, maybe some "design" trick can help me ?
Let's say I have PointValueA and PointValueB inherting, how can i avoid passing creators for each one of them manually ?

I would have thought that the most basic way to handle this is by passing the factory through the constructor, rather than for each call to addPointToList.
public class PointList<PointValueT> where PointValueT : PointValue
{
public PointList(Func<float, PointValueT> pointValueCreator)
{
this.pointValueCreator = pointValueCreator;
}
Func<float, PointValueT> pointValueCreator;
private List<PointValueT> mylist = new List<PointValueT>();
public void addPointToList(float f)
{
mylist.Add(pointValueCreator(f));
}
}
This would then be called like this:
PointList<PointValue> bla = new PointList<PointValue>((myfloat) => new PointValue(myfloat));
bla.addPointToList(f);

You cannot specialise generic in C# like you can with templates in C++.
It would be nice to be able to specify constructor arguments in constraints (i.e. where PointValueT : PointValue, new(float) ), but the language doesn't allow that.
There are a couple of solutions to achieve what you want:
1: use a creator pattern like you're already doing
2: instead of setting the float in the constructor, set it as a property.
public class PointValue
{
public float Value { get; set; }
}
public class PointList<PointValueT>
where PointValueT : PointValue, new()
{
public void addPointToList(float f)
{
// do something to f and then add a new point:
mylist.Add(new PointValueT { Value = f });
}
}
This does mean you can't make your PointValue immutable though.

You can sort of specialize using inheritance
public class PointValueList : PointList<PointValue>
{
public void addPointToList(float f)
{
addPointToList(f, (myfloat) => new PointValue(myfloat));
}
}
and then on that new inherited or specialized class you can just call
bla.addPointToList(f);
Also depending on your needs you can make the base class abstract and declare
public abstract void addPointToList(float f);
in the base class and then override in derived specialization classes
But yes, as Enigmativity suggested, passing factory through the constructor makes more sense at least with this simple example.

Related

C# nameof of generics with constraints on type

Given class:
public interface ITest
{
DateTime DataIns { get; set; }
}
And given the class:
public abstract class ATest<T> where T : class, ITest
{
public void Test() {
// I would like to do this:
// var field = nameof(T.DataIns);
}
}
Is it not possible to get the nameof interface property without using the interface itself? I know that, of course, is possible to do that var field = nameof(IMetrics.DataIns); , but I would like to refer to the generics type.
Looks like it is unlikely to happen: https://github.com/dotnet/csharplang/issues/810
You can cheat a bit and go via something that generates a T symbol, since nameof is a compile-time construct. In some sense this is better than coding against the interface as it does the right thing at compilation, however that's more a matter of opinion.
public abstract class ATest<T> where T : class, ITest
{
public void Test()
{
var field = nameof(THack.DataIns);
}
static T THack => throw new NotImplementedException();
}
Considering that this can be done, it is a bit silly that you cannot use T directly.

Inheritance and Generic Types

i have a problem to create my code structure i don't now how to make it work
the problem in PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack1>();
where it connot be converted
here is the code sample
public class PlayListInfo<_VerseTrack> : IPlayListInfo
where _VerseTrack : VerseTrack
{
public List<_VerseTrack> Tracks;
}
public class VerseTrack1: VerseTrack
{
}
public class VerseTrack2: VerseTrack
{
}
public class player
{
PlayListInfo<VerseTrack> ProgresList;
}
public class player1:player
{
PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack1>();
}
public class player2:player
{
}
Generic types aren't inherited based on their type parameters. A PlayListInfo<QuranVerseTrack> is not a PlayListInfo<VerseTrack>
You could do:
PlayListInfo<VerseTrack1> ProgresList = new PlayListInfo<VerseTrack1>();
and then treat all of the items like a VerseTrack, but it's unclear if that's what you should do.
or you could do:
PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack>();
and then add VerseTrack1 (or VerseTrack2) items to it (assuming it's a collection of some sort).
Side note: player1.ProgresList is hiding the base property, not overriding it.
If you are using .NET 4.0 or higher, here's another workaround. I introduce you covariance and contravariance
Assuming A is convertible(implicit reference conversion is available) to B,
X is covariant if X<A> is convertible to X<B>
Since covariance and contravariance only work with interface, you need to modify IPlayListInfo like this:
public interface IPlayListInfo<out _VerseTrack>
where _VerseTrack : VerseTrack
{
// blah blah ...
}
And this might work!
public class player1:player
{
// PlayListInfo<VerseTrack> ProgresList = new PlayListInfo<VerseTrack1>(); // old one
IPlayListInfo<VerseTrack> ProgressList = new PlayListInfo<VerseTrack1>() as IPlayListInfo<VerseTrack1>;
}

Generic collection in generic class

I have a custom class (let's call it MyClass) that looks like this:
public class MyClass
{
private List<MyClass> list;
private object data;
}
However, I want to get rid of the object property and instead use a generic class. So something like this:
public class MyClass<T>
{
private List<MyClass<T>> list;
private T data;
}
However, I am in need for this behavior:
MyClass<Foo> foo = new MyClass<Foo>;
foo.list = new List<MyClass<Bar>>;
So I need to be able to have different datatypes for the foo-instance and the list/data-property in foo. But the T's in the generic example will be the same and only allow this:
MyClass<Foo> foo = new MyClass<Foo>;
foo.list = new List<MyClass<Foo>>;
Each item in foo.list will again have a list that might be of a different type. By the time I compile MyClass I have no knowledge about what datatypes will be in the lists/data-property or how many levels there will be. How can I build this flexible structure?
Generics are designed to allow for the compiler to perform checks on type usage and they also provide some nifty additional benefits.
What you've described cannot be achieved with generics, if each time you're updating list with a list of a potentially different type then generics cannot help you.
However, if each of these types share a common base type or share a common interface then you could use that as your T for the list and that would allow you to use them.
If however each instance of MyClass allows only one type of List of MyClass<?> then you could revise MyClass as such:
public class MyClass<T, TList>
{
private List<MyClass<T, TList>> list;
private T data;
}
You can't achieve this goal with just one class. You will have to build one generic base class for each level with children, one base class for the lowest level without children and one derived class per hierarchy level.
The base classes would look like this:
public class MyClass<TData>
{
public TData Data { get; set; }
}
public class MyClass<TData, TDataChildren, TChildren> : MyClass<TData>
where TChildren : MyClass<TDataChildren>
{
public List<TChildren> List { get; set; }
}
The derived classes per Level would look like this:
public class Level0 : MyClass<Foo, Bar, Level1> { }
public class Level1 : MyClass<Bar, Fubar, Level2> { }
public class Level2 : MyClass<Fubar> { }
Usage:
var root = new Level0();
root.Data = new Foo();
root.List = new List<Level1>
{
new Level1()
{
Data = new Bar(),
List = new List<Level2>
{
new Level2()
{
Data = new Fubar()
}
}
}
};
Add a second type in MyClass.
public class MyClass<T, G>
{
private List<MyClass<G, T>> list;
private T data;
}
This is assuming that you don't care the type of the nested list inside your list.
But can you elaborate a bit more on the utility of your code because it is hard to tel just with abstract data.
I am trying to implement a very similar thing in C++ right now and am running into the same problem. The problem with templates is that they are strongly typed and MyClass<foo> is treated as a complete different and unrelated type as MyClass<bar>.
What I am playing with now is creating an abstract class that has pure virtual methods on it like GetInt, GetDouble, GetBool, GetString. I then want to have a templated Add that will instantiate the appropriate concrete class and add it to my vector. I'm not sure if it will work, but it's along these lines:
class Data
{
public:
template<typename T> Add(const std::string& key, const T& val)
{
Data* pData = NULL;
//test the type using std::numeric_limits to figure out which concrete
//type to use.
m_mapValues[key] = pData;
}
protected:
virtual int GetInt() const = 0;
virtual unsigned int GetUINT() const = 0;
virtual std::string GetString() const = 0;
//blah blah more types that you want to handle
private:
std::map<std::string,Data*> m_mapValues;
};
class UINTData : public Data
{
//implement pure virtual methods.
}
This is obviously incomplete, but I hope it gives you some ideas.

Wildcard equivalent in C# generics

Let's say I have a generic class as follows:
public class GeneralPropertyMap<T>
{
}
In some other class I have a method that takes in an array of GeneralPropertyMap<T>. In Java, in order to take in an array that contains any type of GeneralPropertyMap the method would look like this:
private void TakeGeneralPropertyMap(GeneralPropertyMap<?>[] maps)
{
}
We use the wildcard so that later we can call TakeGeneralPropertyMap passing a bunch of GeneralPropertyMap with any type for T each, like this:
GeneralPropertyMap<?>[] maps = new GeneralPropertyMap<?>[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
//And finally pass the array in.
TakeGeneralPropertyMap(maps);
I'm trying to figure out an equivalent in C# with no success. Any ideas?
Generics in C# make stronger guarantees than generics in Java. Therefore, to do what you want in C#, you have to let the GeneralPropertyMap<T> class inherit from a non-generic version of that class (or interface).
public class GeneralPropertyMap<T> : GeneralPropertyMap
{
}
public class GeneralPropertyMap
{
// Only you can implement it:
internal GeneralPropertyMap() { }
}
Now you can do:
private void TakeGeneralPropertyMap(GeneralPropertyMap[] maps)
{
}
And:
GeneralPropertyMap[] maps = new GeneralPropertyMap[3];
maps[0] = new GeneralPropertyMap<String>();
maps[1] = new GeneralPropertyMap<Integer>();
maps[2] = new GeneralPropertyMap<Double>();
TakeGeneralPropertyMap(maps);
While, as others have noted, there's no exact correspondence to wildcards in c#, some of their use cases can be covered with covariance/contravariance.
public interface IGeneralPropertyMap<out T> {} // a class can't be covariant, so
// we need to introduce an interface...
public class GeneralPropertyMap<T> : IGeneralPropertyMap<T> {} // .. and have our class
// inherit from it
//now our method becomes something like
private void TakeGeneralPropertyMap<T>(IList<IGeneralPropertyMap<T>> maps){}
// and you can do
var maps = new List<IGeneralPropertyMap<Object>> {
new GeneralPropertyMap<String>(),
new GeneralPropertyMap<Regex>()
};
//And finally pass the array in.
TakeGeneralPropertyMap<Object>(maps);
The caveat is that you can't use covariance with value types, so adding a new GeneralPropertyMap<int>() to our list fails at compile time.
cannot convert from 'GeneralPropertyMap<int>' to 'IGeneralPropertyMap<object>'
This approach may be more convenient than having a non-generic version of your classes/interfaces in case you want to constrain the types that GeneralPropertyMap can contain. In that case:
public interface IMyType {}
public class A : IMyType {}
public class B : IMyType {}
public class C : IMyType {}
public interface IGeneralPropertyMap<out T> where T : IMyType {}
allows you to have:
var maps = new List<IGeneralPropertyMap<IMyType>> {
new GeneralPropertyMap<A>(),
new GeneralPropertyMap<B>() ,
new GeneralPropertyMap<C>()
};
TakeGeneralPropertyMap(maps);
There is no direct equivalent to this in C#.
In C#, this would often be done by having your generic class implement a non-generic interface or base class:
interface IPropertyMap
{
// Shared properties
}
public class GeneralPropertyMap<T> : IPropertyMap
{
}
You could then pass an array of these:
IPropertyMap[] maps = new IPropertyMap[3];
// ...
TakePropertyMap(maps);
Make an interface from the members of GeneralPropertyMap (IGeneralPropertyMap), and then take an IGeneralPropertyMap[] as an argument.
Actually, you can get pretty close to a wildcard by using dynamic. This also works nicely if you have a non-generic superclass.
For example:
public class A
{
// ...
}
public class B<T> : A
{
// ...
}
public class Program
{
public static A MakeA() { return new A(); }
public static A MakeB() { return new B<string>(); }
public static void Visit<T>(B<T> b)
{
Console.WriteLine("This is B with type "+typeof(T).FullName);
}
public static void Visit(A a)
{
Console.WriteLine("This is A");
}
public static void Main()
{
A instA = MakeA();
A instB = MakeB();
// This calls the appropriate methods.
Visit((dynamic)instA);
Visit((dynamic)instB);
// This calls Visit(A a) twice.
Visit(instA);
Visit(instB);
}
}
How this works is explained in the C# documentation here.

How to handle a collection of Foo<T>, where T can be different for each item?

Problem description
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.
Motivation
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 IUiComponents (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.
Sample Code
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();
}
}
I would suggest you define an interface to invoke the functions you'll want to call as DoSomething<T>(T param). In simplest form:
public interface IDoSomething
{ void DoSomething<T>(T param); }
Next define a base type ElementThatCanDoSomething:
abstract public class ElementThatCanDoSomething
{ abstract public void DoIt(IDoSomething action); }
and a generic concrete type:
public class ElementThatCanDoSomething><T>
{
T data;
ElementThatCanDoSomething(T dat) { data = dat; }
override public void DoIt(IDoSomething action)
{ action.DoIt<T>(data); }
}
Now it's possible to construct an element for any type compile-time T, and pass that element to a generic method, keeping type T (even if the element is null, or if the element is of a derivative of T). The exact implementation above isn't terribly useful, but it can be easily extended in many useful ways. For example, if type T had generic constraints in the interface and concrete type, the elements could be passed to methods which had those constraints on its parameter type (something which is otherwise very difficult, even with Reflection). It may also be useful to add versions of the interface and invoker methods that can accept pass-through parameters:
public interface IDoSomething<TX1>
{ void DoSomething<T>(T param, ref TX1 xparam1); }
... and within the ElementThatCanToSomething
abstract public void DoIt<TX1>(IDoSomething<TX1> action, ref TX1 xparam1);
... and within the ElementThatCanToSomething<T>
override public void DoIt<TX1>(IDoSomething<TX1> action, ref TX1 xparam1)
{ action.DoIt<T>(data, ref xparam1); }
The pattern may easily be extended to any number of pass-through parameters.
EDIT 2: in the case of your overhauled question, the approach is basically the same I've proposed you earlier.
Here I'm adapting it to your scenario and commenting better on what makes it work (plus an unfortunate "gotcha" with value types...)
// note how IPair<T> is covariant with T (the "out" keyword)
public interface IPair<out T> {
T First {get;}
T Second {get;}
}
// I get no bonus points... I've had to touch Pair to add the interface
// note that you can't make classes covariant or contravariant, so I
// could not just declare Pair<out T> but had to do it through the interface
public class Pair<T> : IPair<T> {
public T First {get; set;}
public T Second {get; set;}
// overriding ToString is not strictly needed...
// it's just to "prettify" the output of Console.WriteLine
public override string ToString() {
return String.Format("({0},{1})", First, Second);
}
}
public static class Application {
// Swap now works with IPairs, but is fully generic, type safe
// and contains no casts
public static IPair<T> Swap<T>(IPair<T> pair) {
return new Pair<T>{First=pair.Second, Second=pair.First};
}
// as IPair is immutable, it can only swapped in place by
// creating a new one and assigning it to a ref
public static void SwapInPlace<T>(ref IPair<T> pair) {
pair = new Pair<T>{First=pair.Second, Second=pair.First};
}
// now SwapAll works, but only with Array, not with List
// (my understanding is that while the Array's indexer returns
// a reference to the actual element, List's indexer only returns
// a copy of its value, so it can't be switched in place
public static void SwapAll(IPair<object>[] pairs) {
for(int i=0; i < pairs.Length; i++) {
SwapInPlace(ref pairs[i]);
}
}
}
That's more or less it... Now in your main you can do:
var pairs = new IPair<object>[] {
new Pair<string>{First="a", Second="b"},
new Pair<Uri> {
First=new Uri("http://www.site1.com"),
Second=new Uri("http://www.site2.com")},
new Pair<object>{First=1, Second=2}
};
Application.SwapAll(pairs);
foreach(var p in pairs) Console.WriteLine(p.ToString());
OUTPUT:
(b,a)
(http://www.site2.com/,http://www.site1.com/)
(2,1)
So, your Array is type-safe, because it can only contain Pairs (well, IPairs). The only gotcha is with value types. As you can see I had to declare the last element of the array as a Pair<object> instead of Pair<int> as I would have liked.
This is because covariance/contravariance don't work with value types so I had to box int in an object.
=========
EDIT 1 (old, just leaving there as reference to make sense of the comments below):
you could have both a non-generic marker interface for when you need to act on the container (but don't care about the "wrapped" type) and a covariant generic one for when you need the type information.
Something like:
interface IFoo {}
interface IFoo<out T> : IFoo {
T Value {get;}
}
class Foo<T> : IFoo<T> {
readonly T _value;
public Foo(T value) {this._value=value;}
public T Value {get {return _value;}}
}
Suppose you have this simple hierarchy of classes:
public class Person
{
public virtual string Name {get {return "anonymous";}}
}
public class Paolo : Person
{
public override string Name {get {return "Paolo";}}
}
you could have functions that work either on any IFoo (when you don't care if Foo wraps a Person) or specifically on IFoo<Person> (when you do care):
e.g.
static class Functions
{
// this is where you would do DoSomethingWithContainer(IFoo<?> foo)
// with hypothetical java-like wildcards
public static void DoSomethingWithContainer(IFoo foo)
{
Console.WriteLine(foo.GetType().ToString());
}
public static void DoSomethingWithGenericContainer<T>(IFoo<T> el)
{
Console.WriteLine(el.Value.GetType().ToString());
}
public static void DoSomethingWithContent(IFoo<Person> el)
{
Console.WriteLine(el.Value.Name);
}
}
which you could use like this:
    // note that IFoo can be covariant, but Foo can't,
    // so we need a List<IFoo
var lst = new List<IFoo<Person>>
{
new Foo<Person>(new Person()),
new Foo<Paolo>(new Paolo())
};
foreach(var p in lst) Functions.DoSomethingWithContainer(p);
foreach(var p in lst) Functions.DoSomethingWithGenericContainer<Person>(p);
foreach(var p in lst) Functions.DoSomethingWithContent(p);
// OUTPUT (LinqPad)
// UserQuery+Foo`1[UserQuery+Person]
// UserQuery+Foo`1[UserQuery+Paolo]
// UserQuery+Person
// UserQuery+Paolo
// anonymous
// Paolo
One notable thing in the output is that even the function that only received IFoo still had and printed the full type information which in java would have been lost with type erasure.
It seems that in C#, you have to create a list of Foo, which you use as base type of Foo<T>. However, you can't easily get back to Foo<T> from there.
One solution I found is to add an abstract method to Foo for each function SomeFn<T>(Foo<T>), and implement them in Foo<T> by calling SomeFn(this). However, that would mean that every time you want to define a new (external) function on Foo<T>, you have to add a forwarding function to Foo, even though it really shouldn't have to know about that function:
abstract class Foo {
public abstract void DoSomething();
}
class Foo<T> : Foo {
public override void DoSomething() {
Functions.DoSomething(this);
}
// ...
}
static class Functions {
public static void DoSomething<T>(Foo<T> foo) {
// ...
}
public static void DoSomething(List<Foo> list) {
foreach(Foo item in list)
item.DoSomething();
}
}
A slightly cleaner solution from a design perspective seems to be a Visitor pattern which generalizes the above approach to a degree and severs the coupling between Foo and the specific generic functions, but that makes the whole thing even more verbose and complicated.
interface IFooVisitor {
void Visit<T>(Foo<T> foo);
}
class DoSomethingFooVisitor : IFooVisitor {
public void Visit<T>(Foo<T> foo) {
// ...
}
}
abstract class Foo {
public abstract void Accept(IFooVisitor foo);
}
class Foo<T> : Foo {
public override void Accept(IFooVisitor foo) {
foo.Visit(this);
}
// ...
}
static class Functions {
public static void DoSomething(List<Foo> list) {
IFooVisitor visitor = new DoSomethingFooVisitor();
foreach (Foo item in list)
item.Accept(visitor);
}
}
This would almost be a good solution IMO, if it was easier to create a Visitor. Since C# apparently does not allow generic delegates/lambdas, you cannot specify the visitor inline and take advantage of closures though - As far as I can tell, each Visitor needs to be a new explicitly defined class with possible extra parameters as fields. The Foo type also has to explicitly support this scheme by implementing the Visitor pattern.
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)

Categories