As a followup question to this one
public interface IFeature { }
public class FeatureA : IFeature { }
IFeature a = new FeatureA();
Activate(a);
private static void Activate<TFeature>(TFeature featureDefinition) where TFeature : IFeature
{
}
I undestand, that once the FeatureA is casted to IFeature the generic method will always get IFeature as type parameter.
We have a service with provides us with a list features (List<IFeature>). If we want to iterate over those features, passing each in the generic method, I guess there is no way to get the concrete type in the generic method other than
using reflection
using a dynamic variable to determine the type on runtime (Calling a generic method with the correct derived type)
Since reflection is very costly, I would like to use the dynamic cast. Is there any downside to call the method that way? Somehow I feel dirty when doing that :-)
You can use visitor pattern as follows assuming that you can modify your codebase. Otherwise, use dynamic.
public interface IFeature
{
void Accept(Visitior visitor);
}
public class FeatureA : IFeature
{
public void Accept(Visitior visitor)
{
visitor.Visit(this);
}
}
public class FeatureB : IFeature
{
public void Accept(Visitior visitor)
{
visitor.Visit(this);
}
}
public class Visitior
{
public void Visit<TFeature>(TFeature feature) where TFeature : IFeature
{
Console.WriteLine(typeof(TFeature) == feature.GetType());//True
}
}
static void Main(string[] args)
{
List<IFeature> features = new List<IFeature>
{
new FeatureA(),
new FeatureB()
};
Visitior visitor = new Visitior();
foreach (var item in features)
{
item.Accept(visitor);
}
}
You can obtain the type object for generic/(not generic) type using typeof:
public static T Parse<T>(String value)
{
object result = default(T);
var typeT = typeof (T);
if (typeT == typeof(Guid))
{
result = new Guid(value);
}
else if (typeT == typeof(TimeSpan))
{
result = TimeSpan.Parse(value);
}
else
{
result = Convert.ChangeType(value, typeT);
}
return (T)result;
}
My simple method returns T. And this is a key point. It must be generic to allow developer to specify return type. If method doesn't return generic and only accepts one then there are several reasons to make it generic. To avoid box/unbox operations on method arguments or to tackle with situation when method takes argument of different types which are not inherited from common base class/interface. And it's not your case. So the method in your code haven't to be generic. Just type you argument as IFeature and use is/as/GetType():
private static void Activate(IFeature feature)
{
if (feature is FeatureImplementationA)
{
//Do something...
}
}
Related
Say I have a class CoolStorageClass, which inherits from StorageClassBase:
public abstract class StorageClassBase
{
}
public class CoolStorageClass : StorageClassBase
{
}
Then I have a generic abstract BaseClass<T>. It is important, that T can only be of type StorageClassBase.
public abstract class BaseClass<T> where T : StorageClassBase
{
}
Then I have the implementation of the BaseClass with T as CoolStorageClass in the form of CoolClass:
public class CoolClass : BaseClass<CoolStorageClass>
{
}
I want to select all of my object, which are implementing the BaseClass<StorageClassBase> abstract class.
does it make sense to check the generic of BaseClass? I mean, I could have classes, which inherit from BaseClass<DifferentStorageClassBase>... I ask this, because the linked answer below does not care about the generic parameter of the generic type, only the type itself.
how do I check if a Type implements BaseClass<StorageClassBase>? I have found following answer, but it does not check the type of the generic parameter. So I modified it into this:
public static class TypeExtensions
{
//https://stackoverflow.com/a/457708
public static bool HasBaseClassOf(this Type t, Type toCheck, Type genericParameter)
{
while ((t != null) && (t != typeof(object)))
{
var cur = t.IsGenericType ? t.GetGenericTypeDefinition() : t;
if (toCheck == cur)
{
//also check whether the generic types match
if (t.GenericTypeArguments[0].IsSubclassOf(genericParameter))
{
return true;
}
}
t = t.BaseType;
}
return false;
}
}
But this only checks for one generic type, and I don't understand why I have to check t.GenericTypeArguments instead of cur.GenericTypeArguments.
What is the correct way to check for all the generic type arguments and the BaseClass?
Currently I have to call the function like this: o.GetType().HasBaseClassOf(typeof(BaseClass<StorageClassBase>), typeof(StorageClassBase)). How should I modify the function to be able to call it like this: o.GetType().HasBaseClassOf(typeof(BaseClass<StorageClassBase>))?
Minimal reproducible example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MinimalReproducibleExample
{
public abstract class StorageClassBase
{
//does something
}
public class CoolStorageClass : StorageClassBase
{
}
public abstract class BaseClass<T> where T : StorageClassBase
{
}
public class CoolClass : BaseClass<CoolStorageClass>
{
}
public static class TypeExtensions
{
//https://stackoverflow.com/a/457708
public static bool HasBaseClassOf(this Type t, Type toCheck, Type genericParameter)
{
while ((t != null) && (t != typeof(object)))
{
var cur = t.IsGenericType ? t.GetGenericTypeDefinition() : t;
if (toCheck == cur)
{
//also check whether the generic types match
if (t.GenericTypeArguments[0].IsSubclassOf(genericParameter))
{
return true;
}
}
t = t.BaseType;
}
return false;
}
}
class Program
{
static void Main(string[] args)
{
List<object> myObjects = new List<object>();
myObjects.Add(new CoolClass());
myObjects.Add(new CoolClass());
myObjects.Add(new object());
myObjects.Add(new object());
var t1 = myObjects.Where(o => o.GetType().HasBaseClassOf(typeof(BaseClass<>), typeof(StorageClassBase))).ToList();
Console.ReadKey();
}
}
}
Not sure if this is clear to you or not, but GetGenericTypeDefinition returns a so called open generic type, i.e. baseClass<>. This can be useful if you do not care about the generic arguments for a type. But that does not seem to do quite what you want to.
To simplify the problem statement a bit, lets declare a bunch of shorter types that we can use, simply so we do not have to write BaseClass so many times.
public class T1{}
public class T2 : T1{}
public class Tx : T1{}
public class U1<T> where T : T1{}
public class U2 : U1<T2>{}
public class U2a : U2{}
public class Ux : U1<T1>{}
If I understand your requirements correctly you want to check if a object inherit from a specificed open generic type, and if the type argument is assignable from some other type.
I.e. the following statements should hold:
[Test]
public void Test()
{
Assert.IsTrue(Test<U2>(new U2a()));
Assert.IsTrue(Test<U1<T1>>(new U2()));
Assert.IsTrue(Test<U1<T2>>(new U2()));
Assert.IsTrue(Test<U1<T2>>(new U2a()));
Assert.IsFalse(Test<U1<Tx>>(new U2a()));
Assert.IsFalse(Test<Ux>(new U2a()));
}
The following test should fulfill these statements:
public bool Test<T>(object obj)
{
var tType = typeof(T);
if (tType.IsGenericType)
{
var genericType = tType.GetGenericTypeDefinition();
var genericArguments = tType.GenericTypeArguments;
return obj.GetType().BaseTypes().Any(IsMatchingGenericType);
bool IsMatchingGenericType(Type t)
{
if (!t.IsGenericType)
return false;
if (t.GetGenericTypeDefinition() != genericType)
return false;
if (t.GenericTypeArguments.Length != genericArguments.Length)
{
return false;
}
for (int i = 0; i < genericArguments.Length; i++)
{
if (!genericArguments[i].IsAssignableFrom(t.GenericTypeArguments[i]))
{
return false;
}
}
return true;
}
}
else
{
return tType.IsInstanceOfType(obj);
}
}
This uses IsAssignableFrom rather than IsSubclassOf of, there is some differences between the two if you are using interfaces.
Note that the following does not compile U1<T1> t1 = new U1<T2>(), since the generic type is not covariant. For this you would need to declare a covariant interface, and if you do that, you can just is IsAssignableFrom instead of that large cumbersome method.
I also wonder if you are approaching this in the correct way. It is usually better to put common functionality in separate classes rather than using inheritance. In most cases you want to avoid checking types, and let put the logic in the class instead. If you want to make the logic type-dependent but still separate from the classes, the visitor pattern can often be used.
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;
}
How to do things like this
List<Type:IMyInterface> a = new List<Type:IMyInterface>;
a.Add(typeof(MyClass1)); //MyClass1..3 implementing IMyInterface
a.Add(typeof(MyClass2));
a.Add(typeof(MyClass3));
IMyInterface c = default(a[1]); //create MyClass2 object
a.Add(typeof(Object)); //must fail
without constructing object first or checking type later?
what you want is not directly supported in C#. since Constraints on Type parameter can only be specefied on constructor, inheritance hierarchy, interface implementation and a few others. more details
you can do it in a different way, however in this approach there is no compile time error:
public interface IMyConstraint
{
void Do();
}
public class MyClass: IMyConstraint
{
public void Do()
{
}
}
// Inherit from the List class to add some functionality to it
public class MyTypeList<T> : List<T> where T : System.Type
{
public MyTypeList()
{
}
// use new keyword to prevent client from using the List.Add method.
public new void Add(T type)
{
// here you check if the type is implementing the interface or not
if (!typeof(IMyConstraint).IsAssignableFrom(type))
{
// if it dose not implement the interface just throw an exception
throw new InvalidOperationException();
}
// call the original List.Add method
base.Add(type);
}
}
You can do this if you know the types involved statically:
public class TypeList<T>
{
private readonly List<Type> types = new List<Type>();
public void Add<D>() where D : T, new()
{
this.types.Add(typeof(D));
}
public T NewAt(int index)
{
return (T)Activator.CreateInstance(this.types[index]);
}
}
then you can do:
var a = new TypeList<IMyInterface>;
a.Add<MyClass1>();
a.Add<MyClass2>();
a.Add<MyClass3>();
IMyInterface c = a.NewAt(1);
a.Add<object>(); //won't compile
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.
I have few concrete which uses the following type of interface
interface IActivity<T>
{
bool Process(T inputInfo);
}
Concrete classes are like as follows
class ReportActivityManager :IActivity<DataTable>
{
public bool Process(DataTable inputInfo)
{
// Some coding here
}
}
class AnalyzerActivityManager :IActivity<string[]>
{
public bool Process(string[] inputInfo)
{
// Some coding here
}
}
Now how can i write the factory class which retuns a generic interface some thing like IActivity.
class Factory
{
public IActivity<T> Get(string module)
{
// ... How can i code here
}
}
Thanks
You should create generic method, otherwise compiler will not know type of T in return value. When you will have T you will be able to create activity based on type of T:
class Factory
{
public IActivity<T> GetActivity<T>()
{
Type type = typeof(T);
if (type == typeof(DataTable))
return (IActivity<T>)new ReportActivityManager();
// etc
}
}
Usage:
IActivity<DataTable> activity = factory.GetActivity<DataTable>();
Often this is implemented as in lazyberezovsky's answer. In c++ you could use template specialization to get compiler errors when you try to create a type the factory does not handle.
You can't do that in C# but you can get close. Though the code might look a little surprising which in turn could be a problem.
public static class Factory {
public static IActivity<someType> Get(this someType self){
//stuff specific to someType
}
public static IActivity<someOtherType> Get(someOtherType self){
//stuff specific to someOtherType
}
public static T Creator<T>(){
return null;
}
}
The usage would then be
IActivity<someType> act = Factory.Creator<someType>().Get();
of course this only works if you can pass a concrete type. If you need to pass a type parameter things get more complicated.