I have heard/read the term but don't quite understand what it means.
When should I use this technique and how would I use it? Can anyone provide a good code sample?
The visitor pattern is a way of doing double-dispatch in an object-oriented way.
It's useful for when you want to choose which method to use for a given argument based on its type at runtime rather than compile time.
Double dispatch is a special case of multiple dispatch.
When you call a virtual method on an object, that's considered single-dispatch because which actual method is called depends on the type of the single object.
For double dispatch, both the object's type and the method sole argument's type is taken into account. This is like method overload resolution, except that the argument type is determined at runtime in double-dispatch instead of statically at compile-time.
In multiple-dispatch, a method can have multiple arguments passed to it and which implementation is used depends on each argument's type. The order that the types are evaluated depends on the language. In LISP, it checks each type from first to last.
Languages with multiple dispatch make use of generic functions, which are just function delcarations and aren't like generic methods, which use type parameters.
To do double-dispatch in C#, you can declare a method with a sole object argument and then specific methods with specific types:
using System.Linq;
class DoubleDispatch
{
public T Foo<T>(object arg)
{
var method = from m in GetType().GetMethods()
where m.Name == "Foo"
&& m.GetParameters().Length==1
&& arg.GetType().IsAssignableFrom
(m.GetParameters()[0].GetType())
&& m.ReturnType == typeof(T)
select m;
return (T) method.Single().Invoke(this,new object[]{arg});
}
public int Foo(int arg) { /* ... */ }
static void Test()
{
object x = 5;
Foo<int>(x); //should call Foo(int) via Foo<T>(object).
}
}
The code posted by Mark isn't complete and what ever is there isn't working.
So tweaked and complete.
class DoubleDispatch
{
public T Foo<T>(object arg)
{
var method = from m in GetType().GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic)
where m.Name == "Foo"
&& m.GetParameters().Length == 1
//&& arg.GetType().IsAssignableFrom
// (m.GetParameters()[0].GetType())
&&Type.GetType(m.GetParameters()[0].ParameterType.FullName).IsAssignableFrom(arg.GetType())
&& m.ReturnType == typeof(T)
select m;
return (T)method.Single().Invoke(this, new object[] { arg });
}
public int Foo(int arg)
{
return 10;
}
public string Foo(string arg)
{
return 5.ToString();
}
public static void Main(string[] args)
{
object x = 5;
DoubleDispatch dispatch = new DoubleDispatch();
Console.WriteLine(dispatch.Foo<int>(x));
Console.WriteLine(dispatch.Foo<string>(x.ToString()));
Console.ReadLine();
}
}
Thanks Mark and others for nice explanation on Double Dispatcher pattern.
C# 4 introduces the pseudo type dynamic which resolves the function call at runtime (instead of compile time). (That is, the runtime type of the expression is used). Double- (or multi-dispatch) can be simplified to:
class C { }
static void Foo(C x) => Console.WriteLine(nameof(Foo));
static void Foo(object x) => Console.WriteLine(nameof(Object));
public static void Main(string[] args)
{
object x = new C();
Foo((dynamic)x); // prints: "Foo"
Foo(x); // prints: "Object"
}
Note also by using dynamic you prevent the static analyzer of the compiler to examine this part of the code. You should therefore carefully consider the use of dynamic.
The other answers use generics and the runtime type system. But to be clear the use of generics and runtime type system doesn't have anything to do with double dispatch. They can be used to implement it but double dispatch is just dependent on using the concrete type at runtime to dispatch calls. It's illustrated more clearly I think in the wikipedia page. I'll include the translated C++ code below. The key to this is the virtual CollideWith on SpaceShip and that it's overridden on ApolloSpacecraft. This is where the "double" dispatch takes place and the correct asteroid method is called for the given spaceship type.
class SpaceShip
{
public virtual void CollideWith(Asteroid asteroid)
{
asteroid.CollideWith(this);
}
}
class ApolloSpacecraft : SpaceShip
{
public override void CollideWith(Asteroid asteroid)
{
asteroid.CollideWith(this);
}
}
class Asteroid
{
public virtual void CollideWith(SpaceShip target)
{
Console.WriteLine("Asteroid hit a SpaceShip");
}
public virtual void CollideWith(ApolloSpacecraft target)
{
Console.WriteLine("Asteroid hit ApolloSpacecraft");
}
}
class ExplodingAsteroid : Asteroid
{
public override void CollideWith(SpaceShip target)
{
Console.WriteLine("ExplodingAsteroid hit a SpaceShip");
}
public override void CollideWith(ApolloSpacecraft target)
{
Console.WriteLine("ExplodingAsteroid hit ApolloSpacecraft");
}
}
class Program
{
static void Main(string[] args)
{
Asteroid[] asteroids = new Asteroid[] { new Asteroid(), new ExplodingAsteroid() };
ApolloSpacecraft spacecraft = new ApolloSpacecraft();
spacecraft.CollideWith(asteroids[0]);
spacecraft.CollideWith(asteroids[1]);
SpaceShip spaceShip = new SpaceShip();
spaceShip.CollideWith(asteroids[0]);
spaceShip.CollideWith(asteroids[1]);
}
}
Full listing of working code
using System;
using System.Linq;
namespace TestConsoleApp
{
internal class Program
{
public static void Main(string[] args)
{
const int x = 5;
var dispatch = new DoubleDispatch();
Console.WriteLine(dispatch.Foo<int>(x));
Console.WriteLine(dispatch.Foo<string>(x.ToString()));
Console.ReadLine();
}
}
public class DoubleDispatch
{
public T Foo<T>(T arg)
{
var method = GetType()
.GetMethods()
.Single(m =>
m.Name == "Foo" &&
m.GetParameters().Length == 1 &&
arg.GetType().IsAssignableFrom(m.GetParameters()[0].ParameterType) &&
m.ReturnType == typeof(T));
return (T) method.Invoke(this, new object[] {arg});
}
public int Foo(int arg)
{
return arg;
}
public string Foo(string arg)
{
return arg;
}
}
}
Related
Let's imagine that I have the following overloaded function:
void DoSomething(int x) { ... }
void DoSomething(float x) { ... }
void DoSomething(decimal x) { ... }
In the following method, I need to call the correct overload. This is how a simple implementation would look like:
void HaveToDoSomething(object data)
{
if (data is int) DoSomething((int)data);
else if (data is float) DoSomething((float)data);
else if (data is decimal) DoSomething((decimal)data);
}
This is tedious when there are ~20 types to check. Is there a better way of doing all this casting automatically?
Something I forgot to mention: DoSomething wouldn't work with generics, as each type needs to be handled differently, and I only know the type at runtime.
One possible approach would be to use dynamic:
void HaveToDoSomething(dynamic data)
{
DoSomething(data);
}
You can use Reflection but it can have a performance impact:
public class Example
{
void DoSomething(int i)
{
}
void DoSomething(float i)
{
}
}
public static class ExampleExtensions
{
public static void DoSomethingGeneric(this Example example, object objectParam)
{
var t = objectParam.GetType();
var methods = typeof(example).GetMethods().Where(_ => _.Name == "DoSomething");
var methodInfo = methods.Single(_ => _.GetParameters().First().ParameterType == t);
methodInfo.Invoke(example, new[] { objectParam });
}
}
I have a class with few generic overloaded methods. I am trying to get a specific one by types of its parameters. It's relatively easy to do, when I stick to the first two (with arguments of type int and string). But no matter what I do I cannot get my program to notice the third one, intended for generic list. Do I use a wrong Type argument? If so what is a correct way?
/* rest of code */
static void Main(string[] args) {
MethodInfo method =
typeof(c).GetMethod("m", new Type[] { typeof(int) });
Console.WriteLine(method);
method =
typeof(c).GetMethod("m", new Type[] { typeof(String) });
Console.WriteLine(method);
method =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<>) });
Console.WriteLine(method);
Console.ReadKey();
}
}
static class c
{
public static void m<T>(int i)
{
}
public static void m<T>(String s)
{
}
public static void m<T>(IEnumerable<T> Ls)
{
}
}
Short version: typeof(IEnumerable<>) is not the same as typeof(IEnumerable<T>) (for some T).
Longer version: there is no method void c.m(IEnumerable<> Ls), only overloads where the generic parameter will be some specific – existing at run time – type where the jitter has needed to create the method due to some code referencing that instantiation of the generic method.
Add a call, in your test code, to some instance of the generic method and then do a GetMethod for that instance.
Consider the following:
using System.Collections.Generic;
using System.Linq;
using static System.Console;
class Methods {
public static void M(int x) {
// no-op
}
public static void M<T>(IEnumerable<T> x) {
// no-op
}
}
class Program {
static void Main(string[] args) {
Methods.M(0);
Methods.M(new[] { "a", "b" });
ShowAllM();
}
public static void ShowAllM() {
var tm = typeof(Methods);
foreach (var mi in tm.GetMethods().Where(m => m.Name == "M"))
{
WriteLine(mi.Name);
foreach (var p in mi.GetParameters())
{
WriteLine($"\t{p.ParameterType.Name}");
}
}
}
}
which produces the output:
M
Int32
M
IEnumerable`1
Note there is only one result from the generic overload. If a call to M<char>(…) is added to Main then the output is the same.
For reflection there is just one method, are its argument reflects its "open generic" nature, but that isn't quite the same as being callable with an open generic type (eg. IEnumerable<>) as open types are not instantiatable.
(I've fudged much of the technical details here. It is instruictive to look at the difference in a debugger between typeof(IEnumerable<>) and typeof(IEnumerable<int>).)
The third method has a signature of m<T>(IEnumerable<T>) but your example shows an attempt to find a method with a signature m(IEnumerable<>).
The difference between the typeof(IEnumerable<T>) and typeof(IEnumerable<>) is the the former is a generic type and the second is a generic type definition and these are not the same thing. A generic type is determined from both the generic type definition and the generic type arguments.
With that in mind you would want to use:
method =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<MyType>) });
and substitute the type of enumerable that you will be passing into the method.
On the other hand if you don't know the type of enumerable up front you could get the generic method definition and make the useable generic method when you need it:
methodDef =
typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<object>) }).GetGenericMethodDefinition();
method = methodDef.MakeGenericMethod(new Type[] { typeof(MyType) });
If you remove generic defenitions from int and string methods:
public static void m(int i)
{
}
public static void m(String s)
{
}
public static void m<T>(IEnumerable<T> Ls)
{
}
And use following lines to get needed generic method:
method = typeof(c).GetMethods().FirstOrDefault(m => m.IsGenericMethod &&
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition()
== typeof(IEnumerable<>));
This will do the trick
/// <summary>
/// Will fetch first occurence of IEnumerable<T> method and generate new generic method
/// <para/>
/// that corresponds to Document type
/// </summary>
/// <param name="Document"></param>
/// <param name="MethodName"></param>
/// <returns></returns>
public static MethodInfo GetAppropriateCollectionGenericMethod(object SourceClass, dynamic Document, string MethodName)
{
//get all public methods
var publicMethods = SourceClass.GetType().GetMethods().Where(x => x.Name == MethodName && x.IsGenericMethod);
//filter out only useful methods
foreach (var goodMethod in publicMethods)
{
var methodParams = goodMethod.GetParameters();
var firstParameterType = methodParams[0].ParameterType;
//methods that has arguments like Ienumerable<T>, RepeatedField<T> and so on
var hasNested = firstParameterType.GenericTypeArguments.Length > 0;
if (hasNested == true)
{
//if we found first method with that name that has as parameter an IEnumerable<T> we are ok
var genericTypeDef = firstParameterType.GetGenericTypeDefinition();
if (genericTypeDef == typeof(IEnumerable<>))
{
//Recover current document type, even if it's a list of such types
Type documentType = GetDocumentNestedType(Document);
//simply create a generic method based on Document inner Type
return goodMethod.MakeGenericMethod(documentType);
}
}
}
return null;
}
You will need this, in order to avoid errors:
var hasNested = firstParameterType.GenericTypeArguments.Length > 0;
This will fetch first occurency of:
public static void m<T>(IEnumerable<T> Ls)
{
}
and will generate a method that you can use like that:
var localMethod = GenericReflectionHelper.GetAppropriateCollectionGenericMethod(this, Document, nameof(Insert));
//we are relying on implicit casting
localMethod.Invoke(this, new object[] { Document });
Full sample:
public void Insert<T>(T Document)
{
//Valid for Lists and Repeated Fields
if (Document is IEnumerable)
{
MethodInfo localMethod;
var tuple = Tuple.Create(Document.GetType(), nameof(Insert));
if (CachedMethodsRedirection.ContainsKey(tuple) == true)
{
localMethod = CachedMethodsRedirection[tuple];
}
else
{
localMethod = GenericReflectionHelper.GetAppropriateCollectionGenericMethod(this, Document, nameof(Insert));
CachedMethodsRedirection.Add(tuple, localMethod);
}
//we are relying on implicit casting
localMethod.Invoke(this, new object[] { Document });
}
else
{
DocumentSession.GetCollection<T>().Insert(Document);
}
}
public void Insert<T>(IEnumerable<T> Document)
{
DocumentSession.GetCollection<T>().Insert(Document);
}
Is there a well-known way for simulating the variadic template feature in C#?
For instance, I'd like to write a method that takes a lambda with an arbitrary set of parameters. Here is in pseudo code what I'd like to have:
void MyMethod<T1,T2,...,TReturn>(Fun<T1,T2, ..., TReturn> f)
{
}
C# generics are not the same as C++ templates. C++ templates are expanded compiletime and can be used recursively with variadic template arguments. The C++ template expansion is actually Turing Complete, so there is no theoretically limit to what can be done in templates.
C# generics are compiled directly, with an empty "placeholder" for the type that will be used at runtime.
To accept a lambda taking any number of arguments you would either have to generate a lot of overloads (through a code generator) or accept a LambdaExpression.
There is no varadic support for generic type arguments (on either methods or types). You will have to add lots of overloads.
varadic support is only available for arrays, via params, i.e.
void Foo(string key, params int[] values) {...}
Improtantly - how would you even refer to those various T* to write a generic method? Perhaps your best option is to take a Type[] or similar (depending on the context).
I know this is an old question, but if all you want to do is something simple like print those types out, you can do this very easily without Tuple or anything extra using 'dynamic':
private static void PrintTypes(params dynamic[] args)
{
foreach (var arg in args)
{
Console.WriteLine(arg.GetType());
}
}
static void Main(string[] args)
{
PrintTypes(1,1.0,"hello");
Console.ReadKey();
}
Will print "System.Int32" , "System.Double", "System.String"
If you want to perform some action on these things, as far as I know you have two choices. One is to trust the programmer that these types can do a compatible action, for example if you wanted to make a method to Sum any number of parameters. You could write a method like the following saying how you want to receive the result and the only prerequisite I guess would be that the + operation works between these types:
private static void AddToFirst<T>(ref T first, params dynamic[] args)
{
foreach (var arg in args)
{
first += arg;
}
}
static void Main(string[] args)
{
int x = 0;
AddToFirst(ref x,1,1.5,2.0,3.5,2);
Console.WriteLine(x);
double y = 0;
AddToFirst(ref y, 1, 1.5, 2.0, 3.5, 2);
Console.WriteLine(y);
Console.ReadKey();
}
With this, the output for the first line would be "9" because adding to an int, and the second line would be "10" because the .5s didn't get rounded, adding as a double. The problem with this code is if you pass some incompatible type in the list, it will have an error because the types can't get added together, and you won't see that error at compile time, only at runtime.
So, depending on your use case there might be another option which is why I said there were two choices at first. Assuming you know the choices for the possible types, you could make an interface or abstract class and make all of those types implement the interface. For example, the following. Sorry this is a bit crazy. And it can probably be simplfied.
public interface Applyable<T>
{
void Apply(T input);
T GetValue();
}
public abstract class Convertable<T>
{
public dynamic value { get; set; }
public Convertable(dynamic value)
{
this.value = value;
}
public abstract T GetConvertedValue();
}
public class IntableInt : Convertable<int>, Applyable<int>
{
public IntableInt(int value) : base(value) {}
public override int GetConvertedValue()
{
return value;
}
public void Apply(int input)
{
value += input;
}
public int GetValue()
{
return value;
}
}
public class IntableDouble : Convertable<int>
{
public IntableDouble(double value) : base(value) {}
public override int GetConvertedValue()
{
return (int) value;
}
}
public class IntableString : Convertable<int>
{
public IntableString(string value) : base(value) {}
public override int GetConvertedValue()
{
// If it can't be parsed return zero
int result;
return int.TryParse(value, out result) ? result : 0;
}
}
private static void ApplyToFirst<TResult>(ref Applyable<TResult> first, params Convertable<TResult>[] args)
{
foreach (var arg in args)
{
first.Apply(arg.GetConvertedValue());
}
}
static void Main(string[] args)
{
Applyable<int> result = new IntableInt(0);
IntableInt myInt = new IntableInt(1);
IntableDouble myDouble1 = new IntableDouble(1.5);
IntableDouble myDouble2 = new IntableDouble(2.0);
IntableDouble myDouble3 = new IntableDouble(3.5);
IntableString myString = new IntableString("2");
ApplyToFirst(ref result, myInt, myDouble1, myDouble2, myDouble3, myString);
Console.WriteLine(result.GetValue());
Console.ReadKey();
}
Will output "9" the same as the original Int code, except the only values you can actually pass in as parameters are things that you actually have defined and you know will work and not cause any errors. Of course, you would have to make new classes i.e. DoubleableInt , DoubleableString, etc.. in order to re-create the 2nd result of 10. But this is just an example, so you wouldn't even be trying to add things at all depending on what code you are writing and you would just start out with the implementation that served you the best.
Hopefully someone can improve on what I wrote here or use it to see how this can be done in C#.
Another alternative besides those mentioned above is to use Tuple<,> and reflection, for example:
class PrintVariadic<T>
{
public T Value { get; set; }
public void Print()
{
InnerPrint(Value);
}
static void InnerPrint<Tn>(Tn t)
{
var type = t.GetType();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Tuple<,>))
{
var i1 = type.GetProperty("Item1").GetValue(t, new object[]{});
var i2 = type.GetProperty("Item2").GetValue(t, new object[]{ });
InnerPrint(i1);
InnerPrint(i2);
return;
}
Console.WriteLine(t.GetType());
}
}
class Program
{
static void Main(string[] args)
{
var v = new PrintVariadic<Tuple<
int, Tuple<
string, Tuple<
double,
long>>>>();
v.Value = Tuple.Create(
1, Tuple.Create(
"s", Tuple.Create(
4.0,
4L)));
v.Print();
Console.ReadKey();
}
}
I don't necessarily know if there's a name for this pattern, but I arrived at the following formulation for a recursive generic interface that allows an unlimited amount of values to be passed in, with the returned type retaining type information for all passed values.
public interface ITraversalRoot<TRoot>
{
ITraversalSpecification<TRoot> Specify();
}
public interface ITraverser<TRoot, TCurrent>: ITraversalRoot<TRoot>
{
IDerivedTraverser<TRoot, TInclude, TCurrent, ITraverser<TRoot, TCurrent>> AndInclude<TInclude>(Expression<Func<TCurrent, TInclude>> path);
}
public interface IDerivedTraverser<TRoot, TDerived, TParent, out TParentTraverser> : ITraverser<TRoot, TParent>
{
IDerivedTraverser<TRoot, TInclude, TDerived, IDerivedTraverser<TRoot, TDerived, TParent, TParentTraverser>> FromWhichInclude<TInclude>(Expression<Func<TDerived, TInclude>> path);
TParentTraverser ThenBackToParent();
}
There's no casting or "cheating" of the type system involved here: you can keep stacking on more values and the inferred return type keeps storing more and more information. Here is what the usage looks like:
var spec = Traversal
.StartFrom<VirtualMachine>() // ITraverser<VirtualMachine, VirtualMachine>
.AndInclude(vm => vm.EnvironmentBrowser) // IDerivedTraverser<VirtualMachine, EnvironmentBrowser, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>
.AndInclude(vm => vm.Datastore) // IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>
.FromWhichInclude(ds => ds.Browser) // IDerivedTraverser<VirtualMachine, HostDatastoreBrowser, Datastore, IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>>
.FromWhichInclude(br => br.Mountpoints) // IDerivedTraverser<VirtualMachine, Mountpoint, HostDatastoreBrowser, IDerivedTraverser<VirtualMachine, HostDatastoreBrowser, Datastore, IDerivedTraverser<VirtualMachine, Datastore, VirtualMachine, ITraverser<VirtualMachine, VirtualMachine>>>>
.Specify(); // ITraversalSpecification<VirtualMachine>
As you can see the type signature becomes basically unreadable near after a few chained calls, but this is fine so long as type inference works and suggests the right type to the user.
In my example I am dealing with Funcs arguments, but you could presumably adapt this code to deal with arguments of arbitrary type.
For a simulation you can say:
void MyMethod<TSource, TResult>(Func<TSource, TResult> f) where TSource : Tparams {
where Tparams to be a variadic arguments implementation class. However, the framework does not provide an out-of-box stuff to do that, Action, Func, Tuple, etc., are all have limited length of their signatures. The only thing I can think of is to apply the CRTP .. in a way I've not find somebody blogged. Here's my implementation:
*: Thank #SLaks for mentioning Tuple<T1, ..., T7, TRest> also works in a recursive way. I noticed it's recursive on the constructor and the factory method instead of its class definition; and do a runtime type checking of the last argument of type TRest is required to be a ITupleInternal; and this works a bit differently.
Code
using System;
namespace VariadicGenerics {
public interface INode {
INode Next {
get;
}
}
public interface INode<R>:INode {
R Value {
get; set;
}
}
public abstract class Tparams {
public static C<TValue> V<TValue>(TValue x) {
return new T<TValue>(x);
}
}
public class T<P>:C<P> {
public T(P x) : base(x) {
}
}
public abstract class C<R>:Tparams, INode<R> {
public class T<P>:C<T<P>>, INode<P> {
public T(C<R> node, P x) {
if(node is R) {
Next=(R)(node as object);
}
else {
Next=(node as INode<R>).Value;
}
Value=x;
}
public T() {
if(Extensions.TypeIs(typeof(R), typeof(C<>.T<>))) {
Next=(R)Activator.CreateInstance(typeof(R));
}
}
public R Next {
private set;
get;
}
public P Value {
get; set;
}
INode INode.Next {
get {
return this.Next as INode;
}
}
}
public new T<TValue> V<TValue>(TValue x) {
return new T<TValue>(this, x);
}
public int GetLength() {
return m_expandedArguments.Length;
}
public C(R x) {
(this as INode<R>).Value=x;
}
C() {
}
static C() {
m_expandedArguments=Extensions.GetExpandedGenericArguments(typeof(R));
}
// demonstration of non-recursive traversal
public INode this[int index] {
get {
var count = m_expandedArguments.Length;
for(INode node = this; null!=node; node=node.Next) {
if(--count==index) {
return node;
}
}
throw new ArgumentOutOfRangeException("index");
}
}
R INode<R>.Value {
get; set;
}
INode INode.Next {
get {
return null;
}
}
static readonly Type[] m_expandedArguments;
}
}
Note the type parameter for the inherited class C<> in the declaration of
public class T<P>:C<T<P>>, INode<P> {
is T<P>, and the class T<P> is nested so that you can do some crazy things such as:
Test
[Microsoft.VisualStudio.TestTools.UnitTesting.TestClass]
public class TestClass {
void MyMethod<TSource, TResult>(Func<TSource, TResult> f) where TSource : Tparams {
T<byte>.T<char>.T<uint>.T<long>.
T<byte>.T<char>.T<long>.T<uint>.
T<byte>.T<long>.T<char>.T<uint>.
T<long>.T<byte>.T<char>.T<uint>.
T<long>.T<byte>.T<uint>.T<char>.
T<byte>.T<long>.T<uint>.T<char>.
T<byte>.T<uint>.T<long>.T<char>.
T<byte>.T<uint>.T<char>.T<long>.
T<uint>.T<byte>.T<char>.T<long>.
T<uint>.T<byte>.T<long>.T<char>.
T<uint>.T<long>.T<byte>.T<char>.
T<long>.T<uint>.T<byte>.T<char>.
T<long>.T<uint>.T<char>.T<byte>.
T<uint>.T<long>.T<char>.T<byte>.
T<uint>.T<char>.T<long>.T<byte>.
T<uint>.T<char>.T<byte>.T<long>.
T<char>.T<uint>.T<byte>.T<long>.
T<char>.T<uint>.T<long>.T<byte>.
T<char>.T<long>.T<uint>.T<byte>.
T<long>.T<char>.T<uint>.T<byte>.
T<long>.T<char>.T<byte>.T<uint>.
T<char>.T<long>.T<byte>.T<uint>.
T<char>.T<byte>.T<long>.T<uint>.
T<char>.T<byte>.T<uint>.T<long>
crazy = Tparams
// trying to change any value to not match the
// declaring type makes the compilation fail
.V((byte)1).V('2').V(4u).V(8L)
.V((byte)1).V('2').V(8L).V(4u)
.V((byte)1).V(8L).V('2').V(4u)
.V(8L).V((byte)1).V('2').V(4u)
.V(8L).V((byte)1).V(4u).V('2')
.V((byte)1).V(8L).V(4u).V('2')
.V((byte)1).V(4u).V(8L).V('2')
.V((byte)1).V(4u).V('2').V(8L)
.V(4u).V((byte)1).V('2').V(8L)
.V(4u).V((byte)1).V(8L).V('2')
.V(4u).V(8L).V((byte)1).V('2')
.V(8L).V(4u).V((byte)1).V('2')
.V(8L).V(4u).V('9').V((byte)1)
.V(4u).V(8L).V('2').V((byte)1)
.V(4u).V('2').V(8L).V((byte)1)
.V(4u).V('2').V((byte)1).V(8L)
.V('2').V(4u).V((byte)1).V(8L)
.V('2').V(4u).V(8L).V((byte)1)
.V('2').V(8L).V(4u).V((byte)1)
.V(8L).V('2').V(4u).V((byte)1)
.V(8L).V('2').V((byte)1).V(4u)
.V('2').V(8L).V((byte)1).V(4u)
.V('2').V((byte)1).V(8L).V(4u)
.V('7').V((byte)1).V(4u).V(8L);
var args = crazy as TSource;
if(null!=args) {
f(args);
}
}
[TestMethod]
public void TestMethod() {
Func<
T<byte>.T<char>.T<uint>.T<long>.
T<byte>.T<char>.T<long>.T<uint>.
T<byte>.T<long>.T<char>.T<uint>.
T<long>.T<byte>.T<char>.T<uint>.
T<long>.T<byte>.T<uint>.T<char>.
T<byte>.T<long>.T<uint>.T<char>.
T<byte>.T<uint>.T<long>.T<char>.
T<byte>.T<uint>.T<char>.T<long>.
T<uint>.T<byte>.T<char>.T<long>.
T<uint>.T<byte>.T<long>.T<char>.
T<uint>.T<long>.T<byte>.T<char>.
T<long>.T<uint>.T<byte>.T<char>.
T<long>.T<uint>.T<char>.T<byte>.
T<uint>.T<long>.T<char>.T<byte>.
T<uint>.T<char>.T<long>.T<byte>.
T<uint>.T<char>.T<byte>.T<long>.
T<char>.T<uint>.T<byte>.T<long>.
T<char>.T<uint>.T<long>.T<byte>.
T<char>.T<long>.T<uint>.T<byte>.
T<long>.T<char>.T<uint>.T<byte>.
T<long>.T<char>.T<byte>.T<uint>.
T<char>.T<long>.T<byte>.T<uint>.
T<char>.T<byte>.T<long>.T<uint>.
T<char>.T<byte>.T<uint>.T<long>, String>
f = args => {
Debug.WriteLine(String.Format("Length={0}", args.GetLength()));
// print fourth value from the last
Debug.WriteLine(String.Format("value={0}", args.Next.Next.Next.Value));
args.Next.Next.Next.Value='x';
Debug.WriteLine(String.Format("value={0}", args.Next.Next.Next.Value));
return "test";
};
MyMethod(f);
}
}
Another thing to note is we have two classes named T, the non-nested T:
public class T<P>:C<P> {
is just for the consistency of usage, and I made class C abstract to not directly being newed.
The Code part above needs to expand ther generic argument to calculate about their length, here are two extension methods it used:
Code(extensions)
using System.Diagnostics;
using System;
namespace VariadicGenerics {
[DebuggerStepThrough]
public static class Extensions {
public static readonly Type VariadicType = typeof(C<>.T<>);
public static bool TypeIs(this Type x, Type d) {
if(null==d) {
return false;
}
for(var c = x; null!=c; c=c.BaseType) {
var a = c.GetInterfaces();
for(var i = a.Length; i-->=0;) {
var t = i<0 ? c : a[i];
if(t==d||t.IsGenericType&&t.GetGenericTypeDefinition()==d) {
return true;
}
}
}
return false;
}
public static Type[] GetExpandedGenericArguments(this Type t) {
var expanded = new Type[] { };
for(var skip = 1; t.TypeIs(VariadicType) ? true : skip-->0;) {
var args = skip>0 ? t.GetGenericArguments() : new[] { t };
if(args.Length>0) {
var length = args.Length-skip;
var temp = new Type[length+expanded.Length];
Array.Copy(args, skip, temp, 0, length);
Array.Copy(expanded, 0, temp, length, expanded.Length);
expanded=temp;
t=args[0];
}
}
return expanded;
}
}
}
For this implementation, I choosed not to break the compile-time type checking, so we do not have a constructor or a factory with the signature like params object[] to provide values; instead, use a fluent pattern of method V for mass object instantiation to keep type can be statically type checked as much as possible.
I've just made the unfortunate (for my app at least) discovery that two methods declared inside a generic class do not have the same base definition, demonstrated best in code:
public static class Test
{
private class Generic<T> { public void Method() { } }
public static void TestBase()
{
var x = typeof(Generic<int>).GetMethod("Method");
var y = typeof(Generic<double>).GetMethod("Method");
Debug.Assert(x.GetBaseDefinition() == y.GetBaseDefinition()); // fails
}
}
Both x and y.IsGeneric is false, so GetGenericMethodDefinition cannot be used.
The only solution I've been able to think of so far is to compare their names and that their declaring types are the same generic type, but in the presence of overloads that seems very brittle..
So.. I don't suppose there's a helpful method I've missed in the reflection library that can tell me if these two methods have been first declared in the same class? Or a workaround?
EDIT:
To clarify, I want to make a method:
public bool DeclaredInSameClass(MethodInfo a, MethodInfo b);
which returns true if both a and b are both first declared in the same class.
Ignoring generics, this is simple: a.GetBaseDefinition() == y.GetBaseDefinition(), but how to handle methods declared within generic classes?
EDIT... one last try:
private class Generic<T> {
public void Method() { }
public void Method(string param) { }
public void OtherMethod() { }
}
private class NonGeneric { public void Method() { } }
static void Main(string[] args)
{
var x = typeof(Generic<int>).GetMethod("Method", new Type[]{});
var y = typeof(Generic<double>).GetMethod("Method", new Type[]{});
var a = typeof(Generic<double>).GetMethod("OtherMethod");
var b = typeof(NonGeneric).GetMethod("Method");
var c = typeof(Generic<int>).GetMethod("Method", new Type[] { typeof(string) });
Debug.Assert(DeclaredInSameClass(x, y));
Debug.Assert(!DeclaredInSameClass(x, a));
Debug.Assert(!DeclaredInSameClass(x, b));
Debug.Assert(!DeclaredInSameClass(x, c));
Debug.Assert(!DeclaredInSameClass(a, b));
}
public static bool DeclaredInSameClass(MethodInfo a, MethodInfo b)
{
if (a.DeclaringType.IsGenericType != b.DeclaringType.IsGenericType)
{
return false;
}
else if (a.DeclaringType.IsGenericType)
{
var x = a.DeclaringType.GetGenericTypeDefinition().GetMethod(a.Name, a.GetParameters().Select(p => p.ParameterType).ToArray());
var y = b.DeclaringType.GetGenericTypeDefinition().GetMethod(b.Name, b.GetParameters().Select(p => p.ParameterType).ToArray());
return x.Equals(y);
}
return a.GetBaseDefinition().Equals(b.GetBaseDefinition());
}
I have a lot of functions which are currently overloaded to operate on int and string:
bool foo(int);
bool foo(string);
bool bar(int);
bool bar(string);
void baz(int p);
void baz(string p);
I then have a lot of functions taking 1, 2, 3, or 4 arguments of either int or string, which call the aforementioned functions:
void g(int p1) { if(foo(p1)) baz(p1); }
void g(string p1) { if(foo(p1)) baz(p1); }
void g(int p2, int p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
void g(int p2, string p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
void g(string p2, int p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
void g(string p2, string p2) { if(foo(p1)) baz(p1); if(bar(p2)) baz(p2); }
// etc.
Note: The implementation of the g() family is just an example
More types than the current int or string might be introduced at any time. The same goes for functions with more arguments than 4. The current number of identical functions is barely manageable. Add one more variant in either dimension and the combinatoric explosion will be so huge, it might blow away the application.
In C++, I'd templatize g() and be done.
I understand that .NET generics are different. I have been fighting them for two hours now trying to come up with a solution that doesn't involve copy and pasting code, to no avail.
C# generics won't require me to type out identical code for a family of functions taking five arguments of either of three types?
What am I missing?
Edit: These functions are used to parse a bunch of arguments (currently either int or string) from some source. Imagine bar() and baz() being able to read both int or string, and the g() family specifying the type and number of arguments to parse (implicitly, by their arguments' types).
Consider using inheritance for this case. I am assuming that foo, bar and baz are inherent to the type (int or string in your case). If this is not true please correct or comment this answer.
using System;
namespace ConsoleApplication3
{
abstract class Param
{
public abstract bool Foo();
public abstract bool Bar();
public abstract void Baz();
public static IntParam Create(int value)
{
return new IntParam(value);
}
public static StringParam Create(string value)
{
return new StringParam(value);
}
}
abstract class Param<T> : Param {
private T value;
protected Param() { }
protected Param(T value) { this.value = value; }
public T Value {
get { return this.value; }
set { this.value = value; }
}
}
class IntParam : Param<int>
{
public IntParam() { }
public IntParam(int value) : base(value) { }
public override bool Foo() { return true; }
public override bool Bar() { return true; }
public override void Baz()
{
Console.WriteLine("int param value is " + this.Value);
}
}
class StringParam : Param<string>
{
public StringParam() { }
public StringParam(string value) : base(value) { }
public override bool Foo() { return true; }
public override bool Bar() { return true; }
public override void Baz()
{
Console.WriteLine("String param value is " + this.Value);
}
}
class Program
{
static void g(Param p1)
{
if (p1.Foo()) { p1.Baz(); }
}
static void g(Param p1, Param p2)
{
if (p1.Foo()) { p1.Baz(); }
if (p2.Bar()) { p2.Baz(); }
}
static void Main(string[] args)
{
Param p1 = Param.Create(12);
Param p2 = Param.Create("viva");
g(p1);
g(p2);
g(p1, p1);
g(p1, p2);
g(p2, p1);
g(p2, p2);
Console.ReadKey();
}
}
}
This would output:
int param value is 12
String param value is viva
int param value is 12
int param value is 12
int param value is 12
String param value is viva
String param value is viva
int param value is 12
String param value is viva
String param value is viva
For a new supported type you:
create a new class that supports the type and extends Param<T>;
implement Foo, Bar and Baz for that new type;
Create a new g method (just one) that has another parameter.
Specially for 3) this would greatly reduce explosion of methods. Now you write a single g method for any given number of parameters. With previous design you had to write, for n parameters, 2^n methods (n = 1 -> 2 methods, n = 2 -> 4 methods, n = 3 -> 8 methods, ..).
Your true problem here is most likely one of design, rather than something generics can be used for. Generics should be used for things that are actually type-agnostic, not as a catch-all to make life a bit easier. Perhaps try posting some actual example code you're using, and someone may have an idea about how to redesign your solution in a way that will allow you to extend it without so much headache.
As a teaser, consider something like this:
public void DoSomethingConditionally<T>(T key, Func<T, bool> BooleanCheck, Action<T> WhatToDo)
{
if (BooleanCheck(key)) WhatToDo(key);
}
And you could call it like this:
DoSomethingConditionally<String>("input", v => v == "hello", s => Console.WriteLine(s));
I've used lambda expressions here, but you could just as easily predefine a few Func<>s that perform some common expressions. This would be a much better pattern than method overloading, and would force you to handle new input types at design time.
Not as optimal as I would like... but what if foo, bar, and baz had generic versions as well?
static bool foo(int input)
{
return input > 5;
}
static bool foo(string input)
{
return input.Length > 5;
}
static void baz(int input)
{
Console.WriteLine(input);
}
static void baz(string input)
{
Console.WriteLine(input);
}
static bool foo<T>(T input)
{
if (input is int) return foo((int)(object)input);
if (input is string) return foo((string)(object)input);
return false;
}
static void baz<T>(T input)
{
if (input is int) baz((int)(object)input);
else if (input is string) baz((string)(object)input);
else throw new NotImplementedException();
}
static void g<T>(T input)
{
if (foo(input))
baz(input);
}
static void g<T, U>(T input, U inputU)
{
g(input);
g(inputU);
}
Use a list of objects.
In the case the number of parameters are unknown at planning time, just use a list of objects. Something like:
void g(params object[] args) {
foreach (object arg in args) {
if ((arg is int) && (foo((int)arg))) baz((int)arg) else
if ((arg is string) && (foo((string)arg))) baz((string)arg)
}
}
(Assuming you have bool foo(int), bool foo(string)...)
So you can call:
g(p1, p2);
g(p1);
g(p1, p2, p3)
with any combination of the types, since every reference derives from object (which it could be many more types than required, int and string, but could be handy in future to support more other types).
This is possible since you could use Reflection to recognize the type at runtime.
Another way to execute a sequence of operation is the use of interfaces, defining the action to execute at certain conditions, on certain objects.
interface IUpdatable {
void Update(object[] data);
}
class object1 : IUpdatable { public void Update(object data) { baz(data); } }
class object2 : IUpdatable { public void Update(object data) { baz(data); } }
void g(params IUpdatable[] args) {
foreach (IUpdatable arg in args) {
arg.Update(args);
}
}
But this way you have to model p1 and p2 (but also p3, as objects implementing an interface, which could be not possible.
I would have done this as a comment to #smink, but I don't have enough rep...
If you extend the Param base class to have implicit operators you are back to not having to wrap the contents in code (though the runtime still incurs the wrapping overhead)...
abstract class Param
{
...
public static implicit operator Param(int value)
{ return new IntParam(value); }
}
If you are using C# / .NET 4.0, you can achieve multiple dispatch using the dynamic feature so you only have to implement a single overload of g based on the number of arguments and the proper foo/bar/baz overloads by type inside each g implementation will be resolved at runtime.
void g(dynamic p1) { if (foo(p1)) baz(p1); }
void g(dynamic p1, dynamic p2) { if (foo(p1)) baz(p1); if (bar(p2)) baz(p2); }
Edit:
Even though you are unable to use C# / .NET 4.0, you can still use this approach using reflection. I've added another foo/bar/baz overload for double showing how well this generalizes and allows you to eliminate duplicate g implementations.
bool foo(int p) {Console.WriteLine("foo(int)=" + p); return p == 0;}
bool foo(string p) {Console.WriteLine("foo(string)=" + p); return p == "";}
bool foo(double p) { Console.WriteLine("foo(double)=" + p); return p == 0.0; }
bool bar(int p) {Console.WriteLine("bar(int)=" + p); return p == 1;}
bool bar(string p) { Console.WriteLine("bar(string)=" + p); return p == ""; }
bool bar(double p) { Console.WriteLine("bar(double)=" + p); return p == 1.1; }
void baz(int p) {Console.WriteLine("baz(int)=" + p);}
void baz(string p) { Console.WriteLine("baz(string)=" + p); }
void baz(double p) { Console.WriteLine("baz(double)=" + p); }
//these object overloads of foo/bar/baz allow runtime overload resolution
bool foo(object p)
{
if(p == null) //we need the type info from an instance
throw new ArgumentNullException();
//may memoize MethodInfo by type of p
MethodInfo mi = typeof(Program).GetMethod(
"foo",
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
null,
new Type[] { p.GetType() },
null
);
if (mi.GetParameters()[0].ParameterType == typeof(object))
throw new ArgumentException("No non-object overload found");
return (bool)mi.Invoke(this, new object[] { p });
}
bool bar(object p)
{
if (p == null)
throw new ArgumentNullException();
MethodInfo mi = typeof(Program).GetMethod(
"bar",
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
null,
new Type[] { p.GetType() },
null
);
if (mi.GetParameters()[0].ParameterType == typeof(object))
throw new ArgumentException("No non-object overload found");
return (bool)mi.Invoke(this, new object[] { p });
}
void baz(object p)
{
if (p == null)
throw new ArgumentNullException();
MethodInfo mi = typeof(Program).GetMethod(
"baz",
BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.NonPublic,
null,
new Type[] { p.GetType() },
null
);
if (mi.GetParameters()[0].ParameterType == typeof(object))
throw new ArgumentException("No non-object overload found");
mi.Invoke(this, new object[] { p });
}
//now you don't need to enumerate your identical implementations of g by type
void g(object p1) { if (foo(p1)) baz(p1); }
void g(object p1, object p2) { if (foo(p1)) baz(p1); if (bar(p2)) baz(p2); }
Unfortunately, generics cannot handle this situation. At least, not well. If you make your methods generic, then just about any type can be passed into them. There won't be an adequate where clause on the generics to limit it to just string and int. If your methods are going to do specific int/string related operations inside them, then generics wont work at all.
Generics in C# are not nearly as powerful as templates in C++, and yes they can cause some major headaches at time. It just takes time to get used to them and get a feel for what they can and cannot do.
This might be a bit heavy handed, but would encapsulating the different parameters types as classes work?:
public abstract class BaseStuff
{
public abstract bool Foo();
public abstract bool Bar();
public abstract void Baz();
public void FooBaz()
{
if(Foo()) Baz();
}
public void BarBaz()
{
if(Bar()) Baz();
}
}
public class IntStuff : BaseStuff
{
private int input;
public IntStuff(int input)
{
this.input = input;
}
public bool Foo()
{
//logic using input for example
return input > 0;
}
//implement Bar and Baz using input
}
public class StringStuff : BaseStuff
{
private string input;
public IntStuff(string input)
{
this.input = input;
}
//Implement Foo, Bar and Baz
}
And then have some G methods somewhere:
public void G(BaseStuff stuff1)
{
stuff1.FooBaz();
}
public void G(BaseStuff stuff1, BaseStuff stuff2)
{
stuff1.FooBaz();
stuff2.BarBaz();
}
And you can then call with:
G(new IntStuff(10), new StringStuff("hello"));
G(new StringStuff("hello"), new StringStuff("world"));
You can use code generation to solve this.
Look at Reflection.Emit. You can also generate code with T4 in Visual Studio.
The types are really getting in the way here. You could also try to solve this with a dynamic language or with the C# 4 dynamic keyword.
If you are using c# 4.0 you can do this with the option parameter
Or you can use object
Foo(object o)
{
if (o is int){ }
else if (o is string){ }
}
Or you can use the generic method Foo<T>(T o){ }