I've got an interface with some generic methods, and I wanted to implement a method with overloads to either accept an instance of a class, or its PK value (which is either an int or GUID but does vary).
I added to methods similar to these examples:
void DoSomething<TKey>(TKey key) where TKey: struct;
void DoSomething<TModel>(TModel model) where TModel : class;
The 'DoSomething' method name on the second of these is highlighted, and the error is
Type 'ISomeStuff' already defines a member called 'DoSomething' with
the same parameter types.
I'm surprised by this as I've clearly defined by parameters to be of different type: one is a class and the other a struct.
Why isn't this sufficient to make the signatures different?
Is possible to do it, you need create something like enable_if from C++
public class ClassTag<V> where V : class { }
public class StructTag<V> where V : struct { }
public void Func<V>(V v, ClassTag<V> dummy = null) where V : class
{
Console.Writeln("class");
}
public void Func<V>(V v, StructTag<V> dummy = null) where V : struct
{
Console.Writeln("struct");
}
public void Func<V>(V? v, StructTag<V> dummy = null) where V : struct
{
Console.Writeln("struct?");
}
static void Main()
{
Func("A");
Func(5);
Func((int?)5);
}
It can be expanded to use any disjoint where to distinguish between overloads.
Only drawback is that It cant be used inside another generic method:
public static void Z1<T>(T t) // where T : class
{
Func(t); //error there
}
public static void Z2<T>(T t) where T : class
{
Func(t); //ok
}
edit
But there is possibility of use dynamic in that case to work around this limitation:
public static void Z1<T>(T t)
{
Func((dynamic)t); //if `T == int` it will call "struct" version
}
Only drawback is run time cost similar to call to Dictionary<,> index.
Jon Skeet has an answer to everything: click me
quote:
the declarations only differ in generic constraints, and constraints
aren't part of the signature
If one wishes to invoke a member generically regardless of whether it has a class constraint or a struct constraint, and have it invoke a method with a suitable constraint, one may define an interface IThingUser<T> to act upon any type T, along with one a class which implements it for value types and another which implements it for class types. Have a static class ThingUsers<T> with a static field TheUser of type IThingUser<T>, and have it populate that field with an instance of one of the above classes, and then ThingUsers<T>.theUser will be able to act upon any sort of T.
public static class GenTest93
{
public interface IThingUser<T> { void ActOnThing(T it); }
class StructUser<T> : IThingUser<T>, IThingUser<Nullable<T>> where T : struct
{
void IThingUser<T>.ActOnThing(T it) { System.Diagnostics.Debug.Print("Struct {0}", typeof(T)); }
void IThingUser<Nullable<T>>.ActOnThing(T? it) { System.Diagnostics.Debug.Print("Struct? {0}", typeof(T)); }
}
class ClassUser<T> : IThingUser<T> where T : class
{
void IThingUser<T>.ActOnThing(T it) { System.Diagnostics.Debug.Print("Class {0}", typeof(T)); }
}
static class ThingUsers<T>
{
class DefaultUser : IThingUser<T>
{
public void ActOnThing(T it)
{
Type t = typeof(T);
if (t.IsClass)
t = typeof(ClassUser<>).MakeGenericType(typeof(T));
else
{
if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
t = t.GetGenericArguments()[0];
t = typeof(StructUser<>).MakeGenericType(t);
}
TheUser = (IThingUser<T>)Activator.CreateInstance(t);
TheUser.ActOnThing(it);
}
}
static IThingUser<T> TheUser = new DefaultUser();
public static void ActOnThing(T it) {TheUser.ActOnThing(it);}
}
public static void ActOnThing<T>(T it) { ThingUsers<T>.ActOnThing(it); }
public static void Test()
{
int? foo = 3;
ActOnThing(foo);
ActOnThing(5);
ActOnThing("George");
}
}
It's necessary to use Reflection to create an instance of StructUser<T> or ClassUser<T> if the compiler doesn't know that T satisfies the necessary constraint, but it's not too hard. After the first time ActOnThing<T>() is used for a particular T, ThingUsers<T>.TheUser will be set to an instance which can be used directly for any future calls toActOnThing(), so performance should be very good.
Note that if given a Nullable<T>, the method creates a StructUser<T> and casts it to IThingUser<Nullable<T>>, rather than trying to create a sometype<Nullable<T>>, since nullable types themselves don't satisfy any constraint.
If you don't need generic parameters and just want to differentiate between these cases at compile time, you can use following code.
void Foo(object a) { } // reference type
void Foo<T>(T? a) where T : struct { } // nullable
void Foo(ValueType a) { } // value type
Related
I have the following base class (omitted version):
class BaseClass
{
}
I create the following derived classes:
class DataPreparationClass<T> : BaseClass
{
}
class DataClass<T,U> : DataPreparationClass<T>
{
public virtual void Start<U>(U arg)
{}
}
class DataClassMain : DataClass<InputData,Data>
{
public override void Start(Data argument)
{
base.Start(argument);
}
}
class DataClassAux : DataClass<InputData,AuxData>
{
public override void Start(AuxData argument)
{
base.Start(argument);
}
}
I have a List<BaseClass> containing various derived instances (there are more derived types) and I intend to call their Start method respectively:
List<BaseClass> instances = GetAllInstance();
foreach(BaseClass instance in instances)
{
object arg = GetArgsForInstance(instance);
// instance.Start(arg); //can't call this
}
However, as their common base is the BaseClass, I can't call Start without casting to...basicly every possible type as their types are unknown at the processing.
If I use dynamic:
((dynamic)target).Start(new Data("starting")); //target is of type DataClassMain<InputData,Data>
I get an exception:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'The best
overloaded method match for
'Client.DataClass<InputData,Data>.Start(Data)' has some invalid
arguments'
So how should I call the unknown method?
So, the most straight forward answer to your question would be to use pattern matching to call the start method.
List<BaseClass> instances = GetAllInstance();
foreach(BaseClass instance in instances)
{
object arg = GetArgsForInstance(instance);
switch(instance){
case DataClassMain d : d.Start((Data)arg); break;
case DataClassAux a : a.Start((AuxData)arg);break;
default: throw new Exception();
}
}
But I do get the feeling this is an convoluted and inappropriate inheritance chain, and you should really consider using a factory and/or strategy pattern instead.
It's assumed that GetArgsForInstance allways will return the correct type with respect to the type it receives as an argument, and that the return types (Data, AuxData and so on) share a common base type. So we could do the type resolution directly with a signature of T GetArgsForInstance<T>(BaseClass b). That way you can make sure you get args of the right type before you return it.
Since the Start overrides just pass along the call generic types, so the overrides in DataClassMain and DataClassAux are unnecessary.
If we modify DataClass a bit we can then do it like this:
class DataClass<T,U> : DataPreparationClass<T>
{
public virtual void Start(U arg)
{
//Do somethin with arg
}
public void Call(Func<BaseClass,U> f){
U data = f.Invoke(this);
Start(data);
}
}
and invoke it with
List<BaseClass> instances = GetAllInstance();
foreach(BaseClass instance in instances)
{
switch(instance)
{
case DataClassMain d : d.Call(GetArgsForInstance<Data>); break;
case DataClassAux a : a.Call(GetArgsForInstance<AuxData>);break;
default: throw new Exception();
}
}
The reason this is preferable is that we can let the compiler ensure that we only pass the appropriate types to the different methods, no casting needed.
But again, such a convoluted inheritance chain should almost always be avoided.
I would say, your questions shows multiple flaws in your model:
by definition of your classes, there is no polymorphism inbetween you Start() methods : Start(Data) do not override Start<U>(U)
by definition of your GetArgsForInstance() method, you have lost the type information you need.
I would add that Classes that are called Classes and Data that are called Data and that are parameterized with their content are way too generic.
That saying, your question implies that you are not wanting to fix those flaws, maybe they are out of your control, so you have to live with it :
instead of not loosing the Type information, you ask for a way to retrieve it.
instead of using polymorphism to retrieve the type from the best place to retrieve do so (in my opinion), which is the Start method itself, you ask for a way to retrieve it in the calling code.
So, what I would try to do is :
rework your GetArgsForInstance() method to be able not to loose this information, for instance, replace it by an object, something like :
class DataClassMain : DataClass<InputData,Data>
{
public override void Start(ArgumentProvider argumentProvider)
{
Data argument = argumentProvider.getArgumentAsData(argumentProvider);
base.Start(argument);
}
}
if not possible, retrieve the types from the inside of the derived classes, for instance something like :
public class DataClassMain : DataClass<InputData,Data>
{
public override void Start(object arg)
{
base.Start(arg);
Data argAsData = (Data) arg;
}
}
if not possible, that means you already have a set of constraint that is making your code hard to maintain, so let's go for a messy reflective thing, but you have to be aware that there is no polymorphism involved and get rid of your 'override' and 'virtual' modifier on Start() methods. Here is a fully working program, which output is :
DataClassMain
DataClassAux
public static void Main(string[] args)
{
List<BaseClass> instances = GetAllInstance();
foreach(BaseClass instance in instances)
{
object value = GetArgsForInstance(instance);
messyInvoke(instance, value);
}
}
private static void messyInvoke(BaseClass instance, object value)
{
MethodInfo method = instance.GetType().GetMethod("Start");
if (method != null)
{
ParameterInfo[] parametersInfos = method.GetParameters();
if (parametersInfos.Length == 1)
{
object[] paramArray = {value};
method.Invoke(instance, paramArray);
}
}
}
public class BaseClass{
public virtual Type GetTypeOfArgs()
{
return typeof(Toto);
}
}
public class DataPreparationClass<T> : BaseClass {}
public abstract class DataClass<T> : DataPreparationClass<T>
{
}
public class DataClassMain : DataClass<Toto>
{
public void Start(Data arg)
{
Console.WriteLine("DataClassMain");
}
}
public class DataClassAux : DataClass<Toto>
{
public void Start(AuxData argument)
{
Console.WriteLine("DataClassAux");
}
}
private static object GetArgsForInstance(BaseClass isntance)
{
if (isntance is DataClassMain)
return new Data();
if (isntance is DataClassAux)
return new AuxData();
throw new ArgumentException();
}
private static List<BaseClass> GetAllInstance()
{
return new List<BaseClass> {new DataClassMain(), new DataClassAux()};
}
public class Toto{}
public class DataClassInputData
{
}
public class Data : DataClassInputData
{
}
public class AuxData : DataClassInputData
{
}
I have a question regarding generics in C#. I would like to treat a generic class/interface as one type in any collection and be able to execute the method in foreach loop.
public interface IRunner<T> where T : struct
{
void Run(T data);
}
public class FooRunner : IRunner<int>
{
public void Run(int data)
{
throw new NotImplementedException();
}
}
public class BarRunner : IRunner<float>
{
public void Run(float data)
{
throw new NotImplementedException();
}
}
Having above structure I cannot assign instances of IRunner into one collection because I would need to provide type
var runners = new List<IRunner<?>>();
What I can do it to create non-generic IRunner interface then I would be able to assign them into collection
public interface IRunner { }
public interface IRunner<T> : IRunner where T : struct
{
void Run(T data);
}
Above construct allows me to gather the runners:
var runners = new List<IRunner> { new BarRunner(), new FooRunner() };
Since IRunner does not contain any method I am not able to execte Run() for any memebers which I would like to.
I know that this might be achived using reflections but I see it as a error-prone and dirty solution.
Is there anyway to achive solution like below:
var runners = new List<IRunner<?>> { new BarRunner(), new FooRunner() };
foreach (var runner in runners)
{
T data = GetData(); // get some data
runner.Run(data);
}
To be able to Run with dynamic types, you may refactor as below. However there is no type checking during compile time, and the app may crash during runtime if inappropriate argument type is passed during method invocation.
public interface IRunner
{
void Run(object value);
}
public interface IRunner<T>:IRunner
{
void Run<T>(T value);
}
public abstract class BaseRunner<T>:IRunner<T>
{
public void Run(object value)
{
if(!(value is T arg))
throw new ArugmentException($"{nameof(value)} must be of type {typeof(T)});
Run(arg);
}
public abstract void Run(T value);
}
public class FooRunner:BaseRunner<int>
{
public override void Run(int value)
{
// your implementation
}
}
Usage:
var runners = new List<IRunner>{new FooRunner(),new BarRunner()};
foreach(var runner in runners) runner.Run(arg);
Best option(at least in terms of readability) I can suggest in this particular case is to use Enumerable.OfType<TResult> method for type check in pair with non-generic IRunner interface:
int i = 1;
foreach (var runner in runners.OfType<IRunner<int>>())
{
runner.Run(i);
}
I can't think of a way of achieving that without doing some boxing or reflection or even loosing type-safety (as highlighted on previous answers), but if your use case allows it, you can instead of having a generic interface IRunner you could have a generic Run method with the struct generic constraint. This will allow you to have a generic store and worry about the value type only when calling the Run method.
public interface IRunner
{
void Run<T>(T data) where T: struct;
}
I would like to differentiate between following cases:
A plain value type (e.g. int)
A nullable value type (e.g. int?)
A reference type (e.g. string) - optionally, I would not care if this mapped to (1) or (2) above
I have come up with the following code, which works fine for cases (1) and (2):
static void Foo<T>(T a) where T : struct { } // 1
static void Foo<T>(T? a) where T : struct { } // 2
However, if I try to detect case (3) like this, it does not compile:
static void Foo<T>(T a) where T : class { } // 3
The error message is Type 'X' already defines a member called 'Foo' with the same parameter types. Well, somehow I cannot make a difference between where T : struct and where T : class.
If I remove the third function (3), the following code does not compile either:
int x = 1;
int? y = 2;
string z = "a";
Foo (x); // OK, calls (1)
Foo (y); // OK, calls (2)
Foo (z); // error: the type 'string' must be a non-nullable value type ...
How can I get Foo(z) to compile, mapping it to one of the above functions (or a third one with another constraint, which I have not thought of)?
Constraints are not part of the signature, but parameters are. And constraints in parameters are enforced during overload resolution.
So let's put the constraint in a parameter. It's ugly, but it works.
class RequireStruct<T> where T : struct { }
class RequireClass<T> where T : class { }
static void Foo<T>(T a, RequireStruct<T> ignore = null) where T : struct { } // 1
static void Foo<T>(T? a) where T : struct { } // 2
static void Foo<T>(T a, RequireClass<T> ignore = null) where T : class { } // 3
(better six years late than never?)
You cannot differentiate the type of method to call based only on the constraints, unfortunately.
So you need to define a method in a different class or with a different name instead.
Further to your comment on Marnix's answer, you can achieve what you want by using a bit of reflection.
In the example below, the unconstrained Foo<T> method uses reflection to farm out calls to the appropriate constrained method - either FooWithStruct<T> or FooWithClass<T>. For performance reasons we'll create and cache a strongly-typed delegate rather than using plain reflection every time the Foo<T> method is called.
int x = 42;
MyClass.Foo(x); // displays "Non-Nullable Struct"
int? y = 123;
MyClass.Foo(y); // displays "Nullable Struct"
string z = "Test";
MyClass.Foo(z); // displays "Class"
// ...
public static class MyClass
{
public static void Foo<T>(T? a) where T : struct
{
Console.WriteLine("Nullable Struct");
}
public static void Foo<T>(T a)
{
Type t = typeof(T);
Delegate action;
if (!FooDelegateCache.TryGetValue(t, out action))
{
MethodInfo mi = t.IsValueType ? FooWithStructInfo : FooWithClassInfo;
action = Delegate.CreateDelegate(typeof(Action<T>), mi.MakeGenericMethod(t));
FooDelegateCache.Add(t, action);
}
((Action<T>)action)(a);
}
private static void FooWithStruct<T>(T a) where T : struct
{
Console.WriteLine("Non-Nullable Struct");
}
private static void FooWithClass<T>(T a) where T : class
{
Console.WriteLine("Class");
}
private static readonly MethodInfo FooWithStructInfo = typeof(MyClass).GetMethod("FooWithStruct", BindingFlags.NonPublic | BindingFlags.Static);
private static readonly MethodInfo FooWithClassInfo = typeof(MyClass).GetMethod("FooWithClass", BindingFlags.NonPublic | BindingFlags.Static);
private static readonly Dictionary<Type, Delegate> FooDelegateCache = new Dictionary<Type, Delegate>();
}
(Note that this example is not threadsafe. If you require thread-safety then you'll either need to use some sort of locking around all access to the cache dictionary, or -- if you're able to target .NET4 -- use ConcurrentDictionary<K,V> instead.)
Drop the struct contraint on the first method. If you need to differentiate between value types and classes you can use the type of the argument to do so.
static void Foo( T? a ) where T : struct
{
// nullable stuff here
}
static void Foo( T a )
{
if( a is ValueType )
{
// ValueType stuff here
}
else
{
// class stuff
}
}
Amplifying my comment to LukeH, a useful pattern if one will need to use Reflection to invoke different actions based upon a type parameter (as distinct from the type of an object instance) is to create a private generic static class something like the following (this exact code is untested, but I've done this sort of thing before):
static class FooInvoker<T>
{
public Action<Foo> theAction = configureAction;
void ActionForOneKindOfThing<TT>(TT param) where TT:thatKindOfThing,T
{
...
}
void ActionForAnotherKindOfThing<TT>(TT param) where TT:thatOtherKindOfThing,T
{
...
}
void configureAction(T param)
{
... Determine which kind of thing T is, and set `theAction` to one of the
... above methods. Then end with ...
theAction(param);
}
}
Note that Reflection will throw an exception if one attempts to create a delegate for ActionForOneKindOfThing<TT>(TT param) when TT does not comply with that method's constraints. Because the system validated the type of TT when the delegate was created, one can safely invoke theAction without further type-checking. Note also that if outside code does:
FooInvoker<T>.theAction(param);
only the first call will require any Reflection. Subsequent calls will simply invoke the delegate directly.
Thankfully this kind of messing around is required less from C# version 7.3
See Whats new in C# 7.3 - Its not very explicit, but it now appears to use the 'where' arguments to some extent during overload resolution.
Overload resolution now has fewer ambiguous cases
Also see Selecting C# Version in your visual studio project
It will still see clashes with the following
Foo(x);
...
static void Foo<T>(T a) where T : class { } // 3
static void Foo<T>(T a) where T : struct { } // 3
But will correctly resolve
Foo(x);
...
static void Foo<T>(T a, bool b = false) where T : class { } // 3
static void Foo<T>(T a) where T : struct { } // 3
If you don't need generic parameters and just want to differentiate between these 3 cases at compile time you can use following code.
static void Foo(object a) { } // reference type
static void Foo<T>(T? a) where T : struct { } // nullable
static void Foo(ValueType a) { } // valuetype
With the latest compilers the RequireX approach can be done without introducing extra types and using only nullable ones (see at the sharplab.io):
using System;
using static Foos;
int x = 1;
int? y = 2;
string z = "a";
Foo(x); // OK, calls (1)
Foo(y); // OK, calls (2)
Foo(z); // OK, calls (3)
class Foos
{
public static void Foo<T>(T a, T? _ = null) where T : struct => Console.WriteLine(1); // 1
public static void Foo<T>(T? a) where T : struct => Console.WriteLine(2); // 2
public static void Foo<T>(T a, T? _ = null) where T : class => Console.WriteLine(3); // 3
}
Actually removing the 2nd parameter in the 3rd method also seems to work:
class Foos
{
public static void Foo<T>(T a, T? _ = null) where T : struct => Console.WriteLine(1); // 1
public static void Foo<T>(T? a) where T : struct => Console.WriteLine(2); // 2
public static void Foo<T>(T a) where T : class => Console.WriteLine(3); // 3
}
I have the following situation.
My Factory class needs to create appropriate Strategy objects based on the input string argument to the CreateStrategy function.
Strategy1, Strategy2 etc are all derived from a common StrategyBase class. However each strategy has a different Validation mechanism which is the type parameter to the Factory class. However, the StrategyValidators are not of any common type and have different interfaces.
Therefore, in the below code, I am unable to specify any common constraint on the StrategyValidator type.
I am new to C# and hence not sure if there exists any mechanism to get over this design issue. Please suggest
public class Factory
{
//Create the appropriate Concrete Implementation class based on the type
public static StrategyBase CreateStrategy<StrategyValidator>(String Type)
{
StrategyBase EnumImp = null;
// WMI based implementation
if (Type == "Type1")
{
s = Strategy1<StrategyValidator>.Instance;
}
else if (Type = "Type2")
{
s = Strategy2<StrategyValidator>.Instance;
}
return s;
}
private StrategyBase s;
}
Here's the intended usage
Factory f = new Factory();
f.CreateStrategy<WMIValidator>("WMI");
f.CreateStrategy<ABCDValidator>("ABCD");
where WMIValidator and ABCDValidator are unrelated types, but the actual classes created by CreateStrategy function are related in a hierarchy e.g. having a common base StrategyBase
Here is a sample code to illustrate the issue
namespace TestCSharp
{
public interface IStrategy
{
};
public interface S1 : IStrategy
{
void f1();
void f2();
};
public class S1Concrete : S1
{
public void f1() { }
public void f2() { }
}
public interface S2 : IStrategy
{
void f3();
void f4();
};
public class S2Concrete : S2
{
public void f3() { }
public void f4() { }
};
public interface ProductBase
{
};
class Product1<T> : ProductBase where T : S1
{
};
class Product2<T> : ProductBase where T : S2
{
};
public class Factory
{
public ProductBase Create<T>(String Type)
{
if (Type == "P1")
return new Product1<T>();
else if (Type == "P2")
return new Product2<T>();
}
};
class Program
{
static void Main(string[] args)
{
Factory f = new Factory();
ProductBase s = f.Create<S1Concrete>("Type1");
}
}
}
The error I get is
The type 'T' cannot be used as type parameter 'T' in the generic type
or method 'TestCSharp.Product1'. There is no boxing conversion or
type parameter conversion from 'T' to 'TestCSharp.S1'.
I don't really understand your scenario fully but as far as I can tell the factory pattern you're using would have to instantiate products using reflection. This is a little ugly because it doesn't give the consumer any hints about what strategy types can be used with a given product name.
public class Factory
{
public ProductBase Create<T>(string name)
{
Type type;
switch (name)
{
case "P1":
type = typeof (Product1<>);
break;
case "P2":
type = typeof (Product2<>);
break;
case "P3":
type = typeof (Product3<>);
break;
default:
return null;
}
type = type.MakeGenericType(typeof (T));
return (ProductBase) Activator.CreateInstance(type);
}
}
I think that the answer in this case is, it depends on what you want Product and Strategy to do. What you seem to be trying to do is splitting your logic in two branches. Then you want to couple it again by using generics, but as you can notice, it won't work.
Consider a scenario, similar to yours above -- But where each class implementing IStrategy has one instead of two methods which does side effect (i.e. print a string). You use generics when the range of types allowed have something in common. In the case I just mentioned, both have a method returning void and accepting no parameters; so we can add a method to IStrategy, for instance:
public interface IStrategy
{
void ExecuteLogic();
};
public class S1 : IStrategy
{
public void ExecuteLogic()
{
OneMethod();
}
void OneMethod()
{
Console.WriteLine("Hello");
}
};
public class S2 : IStrategy
{
public void ExecuteLogic()
{
TotallyDifferentMethod();
}
void TotallyDifferentMethod()
{
Console.WriteLine("World");
}
};
Now, you also said that Strategy1 and Strategy2 have a different validation mechanism. However, it seems to me that you use them in the same method and context (and thus the same parameters and variables), so there must be something that makes them similar. Still, having defined IStrategy in the way we require, we can just use that as a constraint for Create<T>. So, Factory becomes:
public class Factory
{
public ProductBase Create<T>(String Type) where T : IStrategy
{
if (Type == "P1")
return new Product1<T>();
else if (Type == "P2")
return new Product2<T>();
return null;
}
};
But there's still one case. If you don't want Product1 to be called with S2 as a generic type, or Product2 to have S1 as its generic, then why using generics in the first place? You could easily couple the products with their relative strategies and also simplify the code remarkably.
In case I missed something (or the entire question) please leave a comment and I'll try to adapt my answer.
EDIT: since now you've redefined your example and used S1 and S2 as interfaces, I can see what you mean. A way would be defining multiple generic types and constraints for Factory.Create. Example:
public ProductBase Create<T1, T2>(String Type) where T1 : S1 where T2 : S2
It would be impossible otherwise, as you properly stated, because there's no common ancestor of S1 and S2 which can be accepted by your Product classes.
You can change the function to take StrategyValidator as type.
From
public static StrategyBase CreateStrategy<StrategyValidator>(String Type)
To
public static StrategyBase CreateStrategy<T>(String Type) where T:StrategyValidator
To answer you question, You cannot avoid conditional checks.
To simplify the code can move the different combinations ("Type1", "Type2" , etc) to either dictionary or to the configuration if you use Dependency Injection, and then can you reflection.
Example.
if (!dict.ContainsKey(key))
throw New InvalidArgumentException();
StrategyBase EnumImp = null;
var instance = dict[key].MakeGenericType(typeOf(type)).GetProperty("Instance", BindingFlags.Static | BindingFlags.Public )); //dict is Dictionary<string, Type>
Have you considered overloading the Create<> function? I don't have VisualStudio handy right now, but would the following code work for your situation?
namespace ... {
// ... other code here...
public class Factory {
public Product1<T> Create<T>() where T : S1 {
return new Product1<T>();
}
public Product2<T> Create<T>() where T : S2 {
return new Product2<T>();
}
}
class Program {
static void Main(string[] args) {
Factory f = new Factory();
ProductBase s = f.Create<S1Concrete>();
}
}
}
Additionally, you may wish to move your type constraints to a lower level. Consider writing an abstract base ProductBase class (that inherits from an IProductBase interface?) as follows:
class ProductBase<T> : IProductBase where T : IStrategy { }
This may help to alleviate some of your headaches.
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)