I have a generic interface:
public interface IReader<T> where T: Result
{
IEnumerable<T> ReadResults();
}
where Result is a base class and is extended into DetailedResult:
public class Result
{
// ...
}
public class DetailedResult : Result
{
// ... ...
}
Now I have two concrete types for IReader, each of this implementation returns different type, specific to the reader type:
public class DefaultResultReader<Result> : IReader<Result>
{
IEnumerable<Result> ReadResults();
}
and
public class DetailedResultReader<DetailedResult> : IReader<DetailedResult>
{
IEnumerable<DetailedResult> ReadResults();
}
The structure presented above uses generics. I would like to get rid of it if possible, and have some kind of a factory which would create a concrete implementation of IReader for me - DefaultResultReader.ReadResults() method must return Result while DetailedResultReader.ReadResults() must return DetailedResult
My question is how should the abstract factory look for this structure - how to design it so that I can create specific IReader object as requested ?
i didn't get exactly what you want, but i guess you expect something the following :
public interface IReader<T> where T : Result
{
IEnumerable<T> ReadResults();
}
public class Result
{
}
public class DetailedResult : Result
{
// ... ...
}
public class DefaultResultReader : IReader<Result>
{
public IEnumerable<Result> ReadResults()
{
return null;
}
}
public class DetailedResultReader : IReader<DetailedResult>
{
public IEnumerable<DetailedResult> ReadResults()
{
return null;
}
}
public abstract class ResultReaderAbsractFactory
{
public abstract IReader<Result> CreareDefaultResultReader();
public abstract IReader<DetailedResult> CreareDetailedResultReader();
}
public class ConcreteResultRaderFactory : ResultReaderAbsractFactory
{
public override IReader<Result> CreareDefaultResultReader()
{
return new DefaultResultReader();
}
public override IReader<DetailedResult> CreareDetailedResultReader()
{
return new DetailedResultReader();
}
}
If the DefaultResultReader<Result> will always return IEnumerable<Result>, and DetailedResultReader<DetailedResult> will always return IEnumerable<DetailedResult>, I would suggest making the classes
public class DefaultResultReader : IReader<Result>
{
IEnumerable<Result> ReadResults();
}
and
public class DetailedResultReader : IReader<DetailedResult>
{
IEnumerable<DetailedResult> ReadResults();
}
You then have the abstract factory class
public class ReaderFactory
{
public IReader<Result> CreateDefaultResultReader()
{
return new DefaultResultReader();
}
public IReader<DetailedResult> CreateDetailedResultReader()
{
return new DetailedResultReader();
}
}
If you want to make it fully generic, meaning that you do not have to extend this class even if you create new reader types. You can simply make something like this :
public static class ResultReaderFactory
{
public static IEnumerable<T> ReadResults<T>() where T : Result
{
IReader<T> reader = GetReader<T>();
if(reader != null)
{
return reader.ReadResults();
}
return null;
}
public static IReader<T> GetReader<T>() where T : Result
{
// get the first reader implementation from the list
// that matches the generic definition
IReader<T> reader = _instances
.FirstOrDefault(
r => r.GetType()
.GetInterfaces()
.Any(
i => i == typeof(IReader<T>)
)
) as IReader<T>;
return reader;
}
// placeholder for all objects that implement IReader
static IEnumerable<object> _instances;
static ResultReaderFactory()
{
// register all instances of classes,
// that implements IReader interface
_instances = typeof(ResultReaderFactory)
.Assembly
.GetTypes()
.Where(
t => t.GetInterfaces()
.Any(
i => i.Name
.StartsWith("IReader`1")
)
)
.Select(t => Activator.CreateInstance(t));
}
}
To use this you just have to make classes that implements IReader<T> in the same Assembly that ResultReaderFactory is. Then you can just forget about that factory object and simply call it whenever you want with :
ResultReaderFactory.GetReader<DetailedResult>();
// or assuming you've created class ExtremalyDetailedResult
// and ExtremalyDetailedResultReader
ResultReaderFactory.GetReader<ExtremalyDetailedResult>();
This will read all types that implements IReader<T> whenever you start your application. Then it will pack all of those classes ( already instantiated ) in to the List<object> so you can use them later on. This is really slow though because it uses reflections and Linq to determine which IReader<T> implementation to return.
try this online
Related
Given a set of services that each implement a generic interface where the type parameters all have a common base, how can I write a factory method to return an instance of one of these services? There seems to be no way to write a return type for the factory method.
Here is the sample code, with the problematic method at the bottom:
public abstract class Base
{
public int BaseProp { get; set; }
}
public class Derived1 : Base
{
public int DerivedProp1 { get; set; }
}
public class Derived2 : Base
{
public int DerivedProp2 { get; set; }
}
public interface IHandleStuff<T> where T : Base
{
T GetStuff();
void DoStuff(T t);
}
public class Service1 : IHandleStuff<Derived1>
{
public Derived1 GetStuff() => new();
public void DoStuff(Derived1 t){}
}
public class Service2 : IHandleStuff<Derived2>
{
public Derived2 GetStuff() => new();
public void DoStuff(Derived2 t){}
}
public class Consumer
{
public void DoStuff(Base t)
{
var service = GetServiceFor(t);
service.DoStuff(t);
}
private IHandleStuff<Base> GetServiceFor(Base t)
{
return t.BaseProp switch
{
1 => new Service1(), // Cannot convert expression type 'Service1' to return type 'IHandleStuff<Base>'
2 => new Service2(), // An explicit cast to IHandleStuff<Base> compiles but fails at runtime
_ => throw new ArgumentOutOfRangeException()
};
}
}
Update:
Someone pointed out in a comment (now deleted) that the issue in the above code can be resolved by making the DoStuff and GetServiceFor methods in the Consumer class generic. This works, but at some point in the real code we have to call into this from a non-generic method which knows only the base type. So the suggestion only defers the problem.
I have a bunch of data fetchers which all has the almost same signature. The only thing that differs is the return type. The return type is specified as T:
I have this interface:
public interface IDataFetcher<T>
{
T FetchData(MyObject data);
}
Next I have a about 10 implementations of this interface. In de the calling code I want to do something like this:
public class FetchCommandHandler
{
private readonly IEnumerable<IDataFetcher<T>> _fetchers;
public FetchCommandHandler(IEnumerable<IDataFetcher<T>> fetchers) // this of course does not work
{
_fetchers = fetchers;
}
public MyResult Handle()
{
var myObj = new MyObject(); // get object from database
foreach(var fetcher in _fetchers)
{
var result = fetcher.FetchData(myObj);
// do something with result
}
}
}
So, in the end, what I want is not have to inject each DataFetcher<T> implementation in the constructor. I am looking for a way to retreive all the registrations of IDataFetcher<T> from StructureMap.
I am open for every other design that achieves the same result, ie, not inject each implementation in the constructor.
What we can do is introduce another interface for return type and all the types that will be returned will implement it.
Define an interface :
public interface IData
{
}
public interface IDataFetcher<T> where T : IData
{
T FetchData(MyObject data);
}
As an example a type that would be returned:
public class FooData : IData
{
}
and it's DataFetcher implementation will look like:
public class FooDataFetcher : IDataFetcher<FooData>
{
public FooData FetchData(MyObject data)
{
// logic here and return instance of FooData
}
}
Now what we can do is define the Handler class something like:
public class FetchCommandHandler
{
private readonly IEnumerable<IDataFetcher<IData>> _fetchers;
public FetchCommandHandler(IEnumerable<IDataFetcher<IData>> fetchers) // this of course does not work
{
_fetchers = fetchers;
}
public MyResult Handle()
{
var myObj = new MyObject(); // get object from database
foreach(var fetcher in _fetchers)
{
var result = fetcher.FetchData(myObj);
// do something with result
}
}
}
I have next interface
public interface IProperty<T>
{
T Data { get; set; }
}
public abstract class SomeAbsProperty<T> : IProperty<T> where T : class
{
protected SomeAbsProperty(int param1) {}
public abstract T GetData();
public I Data { get; set; }
}
And I have list of childres classes that based on SomeAbsProperty class
they looks like (simple example)
public sealed class ChildrenProperties : SomeAbsProperty<SomeClasss>
{
public ChildrenProperties(int param1):base(param1) {}
public override object GetData()
{
return new SomeClasss()
}
}
I would like to have some factory that would build specific class based on some type
public static class MyFactory
{
public static SomeAbsProperty<T> CreateObject<T>(PropertyName property) where T : class
{
switch (property)
{
case PropertyName.p1:
return new ChildrenProperties1(siteSettings, packageDateContext);
case PropertyName.p2:
return new ChildrenProperties(siteSettings, packageDateContext);
case PropertyName.p3:
return new ChildrenProperties2(siteSettings, packageDateContext);
case PropertyName.p4:
return new ChildrenProperties3(siteSettings, packageDateContext);
default:
return null;
}
}
}
but compelator can't convert my clases to SomeAbsProperty
what would be correct behavior here ?
You can use as casting to SomeAbsProperty<T> generic class, something like
return new ChildrenProperties(10) as SomeAbsProperty<T>;
Of-course you must be sure that ChildrenProperties is indeed SomeAbsProperty (which you know it is if you wrote base classes and factory class). You can not use explicit compile time casting.
Edit:
Maybe its better if factory which creates instances only depends on generic parameter (this will work only if all specializations have different parameter T; I'm not sure if that is your situation). Something like:
public static SomeAbsProperty<T> CreateObject<T>() where T : class
{
Type type = typeof(T);
if (type == typeof(object))
{
return new ChildrenProperties() as SomeAbsProperty<T>;
}
else if (type == typeof(string))
{
return new ChildrenPropertiesString() as SomeAbsProperty<T>;
}
else
{
return null;
}
}
... then you can call factory with something like:
SomeAbsProperty<object> h = MyFactory.CreateObject<object>();
Console.WriteLine(h.GetType().ToString());
SomeAbsProperty<string> h2 = MyFactory.CreateObject<string>();
Console.WriteLine(h2.GetType().ToString());
I want to create a Shim for an Generic Method. But I have a bit a trouble with the Generic in that case.
Here is my example:
class BaseRepository <T> where T: Entity
{
public T[] FindAll()
{
return Method<T>.FindAll()
}
}
class ClassA : base<A>
{
}
class A : Entity
{
}
class ClassB : base<B>
{
}
class B : Entity
{
}
now I want to create a ShimMethod for ClassA and ClassB
ShimBaseRepository<A>.AllInstances.FindAll = (repo) => MethodA();
ShimBaseRepository<B>.AllInstances.FindAll = (repo) => MethodB();
public A MethodA()
{
//Make the Same as MethodB
}
public B MethodB()
{
//Make the Same as MethodA
}
But what if I have mor than 20 "Base" classes? I don't want to create a Delegate/method for every baseClass. I tried something like this:
List<Type> allEntityClasses = (from x in Assembly.GetAssembly(typeof(Entity)).GetTypes()
where !x.IsAbstract && !x.IsInterface
select x).ToList();
foreach(Type type in allEntityClasses=
{
ShimBaseRepository<type????>.AllInstances.FindAll = (repo) => Method();
}
public Entity????? Method()
{
}
In my Unittest I will use the following methods:
ClassA.FindAll()
ClassB.FindAll()
and not:
Base.FindAll()
Edit:
I use Microsoft Fakes,so I can't Change anything in the ShimClass. Here is the generated sourcecode from Shim.
public class ShimBaseRepository<T> : ShimBase<BaseRepository<T>> where T : Entity
{
public static class AllInstances
{
public static FakesDelegates.Func<BaseRepository<T>, T[]> FindAll { [ShimMethod("FindAll", 20)] set; }
}
}
My intention is, that I don't want to create a delegate for every entity, I just want to iterate through all my EntityClasses and create the delegate dynamically. But I have no Idea how I add my Type object in the
ShimBase<T>
Okay, let's discuss this a little.
First of all, here is a straight-forward solution with virtual method:
public class Base<T> where T : Entity
{
public virtual T[] FindAll()
{
return null;
}
}
Then just override FindAll in concrete classes
Or, if you can, make Base abstract and InnerFindAll abstract too.
But, if you need to specify delegate in runtime (as i can see you have a specific Helper for it, but i can't get, why you invoke helper in Base and then you have some undefined in question AllInstances with a Func) this approach won't help. You'll need to implement Strategy pattern with some default strategy assigned in Base. Then you'll have 3 ways to "resolve" strategies in concrete classes:
Hardcode a strategy in constructor of concrete class
Inject strategy to concrete class constructor via DI container
Implement some kind of Mapper which'll return you appropriate Strategy for EntityType (T)
Also, i think you have some troubles with design. I don't see any reason you need to implement FindAll as a lambda injected to a static property of type Func<T> (yep, i think you can replace AllInstances.FindAll with just a static FindAll). So if i were you, i'd use abstract method..
EDIT
Now i got your problem and can give you only a rather ugly solution via reflection... I hoghly don't recomend you to use this since it's really rigour
public class Program
{
static void Main(string[] args)
{
List<Type> allEntityClasses = (from x in Assembly.GetAssembly(typeof(Entity))
.GetTypes().Where(t=>typeof(Entity).IsAssignableFrom(t))
where !x.IsAbstract && !x.IsInterface
select x).ToList();
foreach (var type in allEntityClasses)
{
var genericType = typeof(BaseGeneric<>).MakeGenericType(type);
var helper = new DelegateHelper();
var myLambda = helper.GetLambdaForType(type);
var allInst = genericType.GetProperty("AllInstances").GetValue(null);
if (allInst == null)
{
allInst = Activator.CreateInstance(genericType.GetProperty("AllInstances").PropertyType);
}
allInst.GetType().GetProperty("FindAll").SetValue(allInst,myLambda);
}
}
}
public static class BaseGeneric<T>
{
public static AllInstances<T> AllInstances { get; set; }
}
public class AllInstances<T>
{
public Func<T[]> FindAll { get; set; }
}
public class DelegateHelper
{
public Delegate GetLambdaForType(Type type)
{
var funcType = typeof(Func<>).MakeGenericType(type.MakeArrayType());
var methodInfo = typeof(DelegateHelper).GetMethods().FirstOrDefault(t => t.Name == "FunctionMethod")
.MakeGenericMethod(type);
var #delegate = methodInfo.CreateDelegate(funcType, this);
return #delegate;
}
public T[] FunctionMethod<T>()
{
return new T[10];
}
}
public class Entity
{
}
public class EntityFirst
{
}
public class EntitySecond
{
}
Coming from the Java world, programming with generics and C# is often a headache. Like this one:
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Which results into an InvalidCastException at Something = (ISomething<ISomeObject>)s;. In Java, this would work, and I could even use (if all else fails) the generics wildcard <?>. This is not possible in C#.
While this is just an example that I put together to explain the problematic, how can this exception be eliminated? The only main constraint is that SomeContainer cannot be a generic class
** Note ** : there are many questions about this, but none of them (that I could find) address a generic class member inside a non generic class.
** Update **
Inside the method SetSomething, I added these lines :
Console.WriteLine(s.GetType().IsSubclassOf(typeof(ISomething<SomeObjectA>)));
Console.WriteLine(s.GetType().ToString() + " : " + s.GetType().BaseType.ToString());
foreach (var i in s.GetType().GetInterfaces())
{
Console.WriteLine(i.ToString());
}
which to my surprise output
False
SomeThingA : System.Object
ISomething`1[SomeObjectA]
Is this why I get this exception?
Out keyword will be a fix, if your ISomething only have methods that return T
interface ISomething<out T> where T : ISomeObject
when creating a generic interface, you can specify whether there is an implicit conversion between interface instances that have different type arguments.
It is called Covariance and Contravariance
Eric Lippert have a good series of articles why we need to think about this, here interface variance is used
Here is my code, which works as expected for me
interface ISomeObject { }
class SomeObjectA : ISomeObject { }
class SomeObjectB : ISomeObject { }
interface ISomething<out T> where T : ISomeObject
{
T GetObject();
}
class SomethingA : ISomething<SomeObjectA>
{
public SomeObjectA GetObject() { return new SomeObjectA(); }
}
class SomethingB : ISomething<SomeObjectB>
{
public SomeObjectB GetObject() { return new SomeObjectB(); }
}
class SomeContainer
{
private ISomething<ISomeObject> Something;
public void SetSomething<T>(ISomething<T> s) where T : ISomeObject
{
Something = (ISomething<ISomeObject>)s;
}
}
class TestContainerSomething
{
static public void Test()
{
SomeContainer Container = new SomeContainer();
Container.SetSomething<SomeObjectA>(new SomethingA());
}
}
Sometimes it is useful to let a generic interface implement a non generic one to circumvent the missing <?>
interface ISomething
{
object GetObject();
}
interface ISomething<T> : ISomething
where T : ISomeObject
{
T GetObject();
}
public class SomeImplementation<T> : ISomething<T>
{
public T GetObject()
{
...
}
object ISomething.GetObject()
{
return this.GetObject(); // Calls non generic version
}
}
A collection can then be typed with the non generic interface
var list = new List<ISomething>();
list.Add(new SomeImplementation<string>());
list.Add(new SomeImplementation<int>());