Factory class returning a generic interface - c#

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.

Related

Return generic interface implementation with different generic type

I have created this simple generic interface:
public interface IInitializerSettings<in ViewerType> where ViewerType : Component
{
void Apply(ViewerType dataViewer);
}
And added an implementation for it:
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
Debug.Log("Applied");
}
}
public class CustomGridLayout : CustomLayout
{
// The implementation code
}
Now I try to use it like that:
public IInitializerSettings<CustomLayout> GetDefaultSettings()
{
return new MenuSettings();
}
But I get this error "Cannot convert type MenuSettings to return type IInitializerSettings"
I don't understand why it isn't allowed, CustomGridLayout inherits CustomLayout.
All I could find is this question, but this solution doesn't work for me (I can't use the out keyword).
The reason you cannot do this is because for a contravariant interface (specified by your use of in for the generic type parameter) you cannot implicitly convert it to an instance of a less derived type. I think the bullet points in the docs explains it fairly ok, if you think in terms of IEnumerable<T> (covariant) and Action<T> (contravariant).
As Selvin mentions in the comments the Apply method in MenuSettings expects an instance of CustomGridLayout, so trying to cast MenuSettings to IInitializerSettings<CustomLayout> is not possible because public void Apply(CustomGridLayout dataViewer) cannot handle a CustomLayout as input. Let me give an example:
public class CustomLayout
{
public void SetupCustomLayout() { ... }
}
public class CustomGridLayout : CustomLayout
{
public void SetupGrid() { ... }
}
public class MenuSettings : IInitializerSettings<CustomGridLayout>
{
public void Apply(CustomGridLayout dataViewer)
{
dataViewer.SetupGrid();
}
}
// Later in the code...
var menuSettings = new MenuSettings();
// This cast is what GetDefaultSettings() is trying to do
var genericSettings = (IInitializerSettings<CustomLayout>)menuSettings;
var layout = new CustomLayout();
// Looking at the type of 'genericSettings' this following line should be possible
// but 'MenuSettings.Apply()' is calling 'dataViewer.SetupGrid()' which doesn't exist
// in 'layout', so 'layout' is not a valid input
genericSettings.Apply(layout);
So in relation to the docs you have defined IInitializerSettings<ViewerType> as a contravariant interface, but are trying to use it as a covariant interface - which is not possible.

Factory method that returns generic instance

I have a base service class with virtual method that sets the properties of an object and returns that object.
Then i have one more service which derived from the base service and also overrides the base method. In overriden method, the derived service executes base.DowWork() to set common properties, and then also sets additional properties.
So based on articles here and here I was able to do this using generics.
public interface IResult
{
}
public class BaseResult : IResult
{
public string CommonProperties { get; set; }
}
public class AdditionalResult : BaseResult
{
public string AdditionalProperties { get; set; }
}
public interface IService<T> where T : IResult
{
T DoWork();
}
public class BaseService<T> : IService<T> where T : BaseResult, new()
{
public virtual T DoWork()
{
var t = new T();
t.CommonProperties = "Some Value";
return t;
}
}
public class AdditionalService : BaseService<AdditionalResult>
{
public override AdditionalResult DoWork()
{
var addtionalResult = base.DoWork();
addtionalResult.CommonProperties = "Override value that was set by BaseService";
addtionalResult.AdditionalProperties = "Set additional properties";
return addtionalResult;
}
}
So far so good
Now i want to create a Factory method that will return the instance of a service based on some type. The application will use the factory to get service instance and call DoWork() like below
class Program
{
static void Main()
{
var factory = new MyFactory();
var service = factory.GetService(0);
var iresult = service.DoWork();
// do something here with IResult
}
}
below is the factory method
public class MyFactory
{
public IService<IResult> GetService(int someType)
{
if (someType == 0)
{
return (IService<IResult>)new BaseService<BaseResult>();
}
if (someType == 1)
{
return (IService<IResult>)new AdditionalService();
}
// note I may have more types and services here. But for simplicity i am using only 2
throw new NotSupportedException();
}
}
However i am not able to figure out what should be the signature of this factory method? Based on suggestions here I'm casting service instance but while executing the application I am getting runtime exception
Unable to cast object of type
'BaseService 1[BaseResult]' to
type 'IService 1[IResult]'
if i don't cast the service instance in the Factory then i get compile time error
Cannot implicitly convert type 'BaseService' to
'IService'. An explicit conversion exists (are you missing a
cast?)
See SO question Understanding Covariant and Contravariant interfaces in C#.
You want to use covariance (out keyword). If you add it to your IService interface generic type it works as expected.
public interface IService<out T> where T : IResult
I know SO prefers not to post links but I can't possibly write anything more or better than already answered in that question.

Calling a generic method with interface instances

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...
}
}

Generic Factory with type parameter

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.

Registering Method on Generic Factory with StructureMap

I am trying to use a method on a generic factory class in my structuremap registry. Normally, i would use the following when registering a type using a factory method:
For<Foo>().Use(x => new FooFactory().GetFoo());
And the following when registering a generic type:
For(typeof(ISomeGeneric<>)).Use(typeof(SomeGeneric<>));
How can I combine the two and retrieve a generic type from a generic factory method? I think it should be something like:
For(typeof(IFoo<>)).Use(typeof(x => new FooFactory<>().Create(someParameter));
This just gives a
"Cannot convert lambda expression to type object because it is not a delegate type"
error. I've tried various combinations but am stumped. Any ideas?
Thanks.
This is possible, BUT I would look for an alternative if you can. The issue is that to work with the open generic, you have to use some reflection. This means you will take a performance hit.
public class FooRegistry:Registry
{
public FooRegistry()
{
For(typeof(IFoo<>)).Use(x =>
{
var ParamType = x.BuildStack.Current.RequestedType
.GetGenericArguments()[0];
return BuildUsingFooFactory(ParamType);
});
}
private object BuildUsingFooFactory(Type paramType)
{
var factoryType = typeof (FooFactory<>).MakeGenericType(new[] {paramType});
var createMethod = factoryType.GetMethod("Create");
object factory = Activator.CreateInstance(factoryType);
return createMethod.Invoke(factory, new[] {"SomeParameterString"});
}
}
public class FooFactory<T>
{
public IFoo<T> Create(string param)
{
return new Foo<T>();
}
}
public interface IFoo<T>
{
}
public class Foo<T> : IFoo<T>
{
}
What you are doing in order is the following:
Find out what the requested generic argument is. (ParamType)
Create a non-open generic type for the factory (factoryType)
Grab the create method off of it. (createMethod)
Create an instance of the factory using the Activator (factory)
Call the create method on the factory instance with your some parameter.
StructureMap takes care of casting the output to the right interface.
Better Solution
Instead of using the IFoo directly, use the IFooFactory. This makes it much cleaner, you have an open generic mapping to the IFooFactory<>. Then just get the type of FooFactory you need to generate your objects.
public class FooRegistry:Registry
{
public FooRegistry()
{
For(typeof (IFooFactory<>))
.Use(typeof (FooFactory<>))
.CtorDependency<string>("connection")
.Is("SomeConnectionString");
}
}
public interface IFooFactory<T>
{
IFoo<T> CreateInstance();
}
public class FooFactory<T> : IFooFactory<T>
{
public FooFactory(string connection)
{
}
public IFoo<T> CreateInstance()
{
return new Foo<T>();
}
}
public interface IFoo<T>
{
}
public class Foo<T> : IFoo<T>
{
}

Categories