Design Advice - How to convert these methods to harness C# Generics - c#

I have throughout my application many methods where I load collections. They all (actually most with a couple of differentials) follow the following pattern:
public BaseCollection<ObjectType1> LoadObjectType1(EventHandler handleEvent)
{
var myQuery = ObjectType1.Load(MyServiceContext);
return new DataManager<ObjectType1>().GetData(myQuery , handleEvent, MyServiceContextt);
}
public BaseCollection<ObjectType2> LoadObjectType2(EventHandler handleEvent)
{
var myQuery = ObjectType2.Load(MyServiceContext);
return new DataManager<ObjectType2>().GetData(myQuery , handleEvent, MyServiceContextt);
}
public BaseCollection<ObjectType3> LoadObjectType3(EventHandler handleEvent)
{
var query = ObjectType3.Load(MyServiceContext);
return new DataManager<ObjectType3>().GetData(query, handleEvent, MyServiceContextt);
}
Where ObjectType# are my business objects, e.g. Employee, Department, etc.
I would like to convert these to harness Generics.
Any advice will be greatly appreciated.

You can always create version of these functions that take a generic argument themselves. However, since there is no argument that can allow the compiler to infer the type of the generic argument, you will always have to supply it in the call.
The main issue, is that you're using a static Load method that is implemented on each object type. You would have to pass this in to the call as a delegate:
public BaseCollection<T> Load<T>(EventHandler handleEvent, Func<QueryType> querySelector)
{
var myQuery = querySelector(MyServiceContext);
return new DataManager<T>().GetData(myQuery , handleEvent, MyServiceContext);
}
When calling these version, you would have to specify the type T, as well as pass in a delegate that will return the query object you use to load your data (since it's type specific):
LoadDepositionSampleTypeItemSource<Department>( handler, Department.Load );
EDIT: So, now that you've updated your question I think I understand it a bit better. There's no reason you can't collapse the different methods down to a single overload. If you can refactor the implementation so that the query is not retrieved from the object type, you may be able to improve and consolidate things further. A factory pattern may make things cleaner and more maintainable:
public BaseCollection<T> Load<T>(EventHandler handleEvent)
{
var myQuery = QueryManager.GetQuery<T>(MyServiceContext);
return new DataManager<T>().GetData(myQuery , handleEvent, MyServiceContext);
}

Do you mean you want the methods to be generic? Something like this?
public BaseCollection<T> LoadObject<T>(EventHandler handleEvent)
{
var myQuery = BusinessUtil.Load<T>(MyServiceContext);
return new DataManager<T>().GetData(myQuery, handleEvent, MyServiceContext);
}
Of course, the problem with this is that you can’t easily call the separate static .Load() methods you already have. You will have to declare a single static generic .Load() method, which can return objects of any of your business types. Something like this maybe:
public static class BusinessUtil
{
public static T Load<T>(ServiceContext context)
{
if (typeof(T) == typeof(Object1))
return (T) Object1.Load(context);
if (typeof(T) == typeof(Object2))
return (T) Object2.Load(context);
// ... etc.
}
}
Alternatively, you can require an extra parameter on LoadObject<T> that specifies how to create such an object:
public BaseCollection<T> LoadObject<T>(EventHandler handleEvent,
Func<ServiceContext, T> generator)
{
var myQuery = generator(MyServiceContext);
return new DataManager<T>().GetData(myQuery, handleEvent, MyServiceContext);
}
// ...
var obj = LoadObject(handleEvent, Object1.Load);
This is assuming that myQuery needs to be of type T, which unfortunately the code in your question doesn’t reveal. If it needs to be a different type, maybe some sort of Query<T>?, then you will need to change the T inside the Func<> (and the return type of BusinessUtil.Load) to that too.

You could use Reflection:
public BaseCollection<T> LoadGeneric<T>(EventHandler handleEvent)
{
var myQuery = (YourQueryType)typeof(T)
.GetMethod("Load")
.Invoke(null, new object[] { MyServiceContext });
return new DataManager<T>().GetData(myQuery , handleEvent, MyServiceContextt);
}
But I think refactoring the code (maybe using single static method as Timwi suggested) would be a better choice.

Related

Choose interface child by some property

I have an interface:
public interface IPath
{
// Some method
}
and I have two classes which are inheriting this interface
public class First : IPath { }
public class Second: IPath { }
By the way, in some method I need to choose which class to use, First or Second, it depending on one string property (type), which I get from database. It looks like:
public void SomeMethod(string type)
{
if (type == "First") { // creating instance of First class }
else if (type == "Second") { // creating instance of Second class }
else { ... }
}
Question is: how can I avoid if/else or switch/case constructions and automaticly create the right instance, depending on the string variable?
You could create a dictionary to map from string to Type and the use that Type and Activator.CreateInstance to create an instance of that type.
Alternatively you could fetch the type using reflection and not need a dictionary at all
private Dictionary<string, Type> _iPathMapping = new Dictionary<string, Type>
{
{ nameof(First), typeof(First) },
{ nameof(Second), typeof(Second) },
};
// ...
public IPath Create(string path)
{
var type = _iPathMapping[path];
return (IPath) Activator.CreateInstance(type);
}
(You'd want to extend that code with safety checks, see below)
But this is fundamentally a bad solve. The problem to this is that it's harder to pass parameters to constructors and it's unsafe as well, if any of your implementations don't have a parameterless constructor, this will fail, but not with a compiler error, no it will fail during runtime, i.e once a user (or hopefully testers/ automatic tests) ran into the problem. So a better way would be to store a method that's invoked to construct the type instead of using Activator.CreateInstance, something like
private Dictionary<string, Func<IPath>> _iPathMapping = new Dictionary<string, Func<IPath>>
{
{ nameof(First), () => new First() },
{ nameof(Second), () => new Second() },
};
// ...
public IPath Create(string path)
{
if (_iPathMapping.TryGetValue(path, out var func))
return func.Invoke();
return null;
}
This solves the problem of parameters for the constructor in that it doesn't throw a runtime exception.
But we still haven't solved the problem of actually passing parameters to the constructor, especially when First and Second require different parameters. The only clean* way to I can think of to handle this in a generic and reusable way is using a Dependency Injection framework/ context to actually construct our instances.
But in general, the if/ else if chain or switch statement isn't necessarily a bad thing, you even see it in some places inside .NET
* You could replicate the part of a DI framework that's responsible for resolving dependencies for a constructor, but that's just re-implementing the wheel and might as well save the effort needed and just pull in a dependency like Microsoft.Extensions.DependencyInjection
I have a shorter version as answer, but I saw "MindSwipe" already offered you one:
Dictionary<string, Type> map = new Dictionary<string, Type>();
map.Add("First", typeof(First));
map.Add("Second", typeof(Second));
var instance = Activator.CreateInstance(map[<your parameter as string>]);

How to be working with a generic IEnumerable<T>?

I have written a function which will take a generic IEnumerable and map these objects (if possible) to objects I want to use for an algorithm. I don't have a lot of experience with generic objects or IEnumerables, so I wanted to ask for some advice.
I have written this code:
public static IEnumerable<OtherObject> MyObjectToOtherObject<T>(IEnumerable<T> objects)
{
if (objects.GetType() == typeof(MyObject))
{
var data = (IEnumerable<MyObject>)objects;
return data.Select(x => new OtherObject() { // Map the attributes });
}
else
return null;
}
This doesn't work in my code, since it returns null even though the input list is of the type MyObject. I just can't figure out how to cast my IEnumerable<T> to IEnumerable<MyObject>. Is there something I'm doing wrong?
Thanks in advance!
I'm sorry for all the confusion. I have asked this the wrong way. Alex has helped me enough, thank you!
this is wrong.
objects.GetType() == typeof(MyObject)
Correct:
objects.GetType() == typeof(IEnumerable<T>)
If you need to compare type of nested items:
objects.GetType().GetGenericArguments()[0] == typeof(MyObject)
typeof(T) == typeof(MyObject)
If you are checking if the type can be casted to another type:
objects.GetType().GetGenericArguments()[0].IsAssignableFrom(typeof(MyObject))
or just as
typeof(T).IsAssignableFrom(typeof(MyObject))
Doesn't look like you need a generic method, if you always know the source and destination types, you can do this:
public static IEnumerable<DestObject> ObjectToObject1(IEnumerable<SourceObject> objects)
{
return data.Select(x => new DestObject() { // Map the attributes });
}
I think what you're trying to do is build a generic mapping method which can map any give T to your concrete class Object1. You need to provide a mapping function which does the mapping.
Say you have this (overly contrived) example:
public class SourceObject
{
public string AString{get;set;}
}
public class DestObject
{
public string TheProperty{get;set;}
}
And you start with an IEnumerable<SourceObject> your method would need to take the list, and a Func<SourceObject,DestObject> to do the mapping
var input = new List<SourceObject>(){
new SourceObject{AString="Str1"},
new SourceObject{AString="Str2"}
};
var result = MyObjectToOtherObject(input, x => new DestObject{TheProperty = x.AString});
This is accomplished like so:
public static IEnumerable<DestObject> MyObjectToOtherObject<T>(IEnumerable<T> objects, Func<T,DestObject> mapping)
{
return data.Select(mapping);
}
As you can see, the separate method is more-or-less useless at this point. It's exactly what Select does.
objects will never be of type MyObject, therefore
(objects.GetType() == typeof(MyObject))
will always return false because object is some generic collection (IEnumerable<T>).
you could try using
typeof(T) == typeof(MyObject)

How to simulate method overloading based on generic return type in c#

I have a read model as IQueryable<CustomType>, I use this inside my Web application. A lot of time I need to extract from this read model different View Model.
I use to write extension method like:
public static ViewModelA AsViewModelA(this IQueryable<CustomType> query)
{
var vm = view
.Select(x => new ViewModelA
{
Something = x.Something
}).FirstOrDefault();
return vm;
}
public static ViewModelB AsViewModelB(this IQueryable<CustomType> query)
{
var vm = view
.Select(x => new ViewModelB
{
SomethingElse = x.SomethingElse
}).FirstOrDefault();
return vm;
}
This do the job but I don't like the mess generated with method names; a more generic way, something like this would be preferable:
query.AsViewModel<ViewModelA>()
I know that return type is not intended as method signature (so no overload applies) and I know that generic type is not sufficient to make an overload.
What I would is a mechanism to just simulate overloading based on generic type. This mechanism should avoid a main method with cascading if/then/else. There is a way? Maybe with dynamics?
One option is to have a map from the type to a conversion of CustomType to that type. So it would look something like:
private static readonly Dictionary<Type, Expression> Mappings =
new Dictionary<Type, Expression>
{
{ typeof(ViewModelA),
Helper<ViewModelA>(x => new ViewModelA { Something = x.Something }) },
{ typeof(ViewModelB),
Helper<ViewModelB>(x => new ViewModelB { SomethingElse = x.SomethingElse }) },
...
}
// This method just helps avoid casting all over the place.
// In C# 6 you could use an expression-bodied member - or add a
private static Expression<Func<CustomType, T>> Helper<T>
(Expression<Func<CustomType, T>> expression)
{
return expression;
}
public static T AsViewModel<T>(this IQueryable<CustomType> query)
{
Expression rawMapping;
if (!Mappings.TryGetValue(typeof(T), out rawMapping))
{
throw new InvalidOperationException("Or another exception...");
}
// This will always be valid if we've set up the dictionary properly
var mapping = (Expression<Func<CustomType, T>>) rawMapping;
return view.Select(mapping).FirstOrDefault();
}
You can make the dictionary construction a bit cleaner with a bit more up-front code.
Well, yes, you can use dynamic:
private static ViewModelA AsViewModelInternal(this IQueryable<CustomType> query,
ViewModelA dummy) { ... }
private static ViewModelB AsViewModelInternal(this IQueryable<CustomType> query,
ViewModelB dummy) { ... }
public static T AsViewModel<T>(this IQueryable<CustomType> query)
{
return (T)query.AsViewModelInternal(default(T));
}
Make sure to handle a non-existing overload, of course :) The easiest way is to add an overload that takes object as the last argument, so that you basically have a "fallback overload".
However, I wouldn't recommend that. One of the great benefits of generics is you get great compile-time checks. This generic method pretends to accept all possible T's, but it actually doesn't. It's the equivalent of taking object instead of ViewModelA/ViewModelB.
It's not like there's a world's difference between
query.AsViewModelB()
and
query.AsViewModel<ViewModelB>()
I'd only use the alternative if you often find yourself having to use a generic type argument when calling AsViewModel, i.e. when you don¨t know the specific 'type in advance.

Create Generic Type with Generic Interface at Run Time

I've been working through an issue for a couple of hours now, and I think I'm close. I'm working on an app where we could have 50-100 types that perform the same way. So instead of creating 50-100 classes, I tried to make it generic and this is what I have:
This is the base class:
public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity
And this is the interface:
public interface IRavenWriter<T>
{
int ExecutionIntervalInSeconds { get; }
void Execute(object stateInfo);
void Initialize(int executionIntervalInSeconds, Expression<Func<T, DateTime>> timeOrderByFunc);
}
And this is how I'm using it:
private static void StartWriters()
{
Assembly assembly = typeof(IDataEntity).Assembly;
List<IDataEntity> dataEntities = ReflectionUtility.GetObjectsForAnInterface<IDataEntity>(assembly);
foreach (IDataEntity dataEntity in dataEntities)
{
Type dataEntityType = dataEntity.GetType();
Type ravenWriterType = typeof(RavenWriterBase<>).MakeGenericType(dataEntityType);
Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime;
// This is where I'm stuck. How do I activate this as RavenWriterBase<T>?
var ravenWriter = Activator.CreateInstance(ravenWriterType);
//ravenWriter.Initialize(60, func); // I can't do this until I cast.
// More functionality here (not part of this issue)
}
}
I'm stuck on this line from above:
var ravenWriter = Activator.CreateInstance(ravenWriterType);
This is my question:
How can I use that as RavenWriterBase or IRavenWriter? Something like:
ravenWriter.Initialize(60, func);
I think it needs to be something like this, but I need to specify a type for IRavenWriter<> and I don't know it yet:
var ravenWriter = Activator.CreateInstance(ravenWriterType) as IRavenWriter<>;
If I hover over ravenWriter, I successfully have my object:
But now I need to be able to use it in a generic way. How can I do that?
Update:
I just thought of using the dynamic keyword, and this works:
dynamic ravenWriter = Activator.CreateInstance(ravenWriterType);
ravenWriter.Initialize(60);
I cheated a bit because I realized that the Func was the same for each IDataEntity, so that wasn't necessary to pass as a parameter to Initialize(). However, at least now I can call Initialize(). But now that the Func is the same, I shouldn't need the generic interface either.
My solution would be to:
Create a non-generic interface of IRavenWriter
Make IRavenWriter<T> inherit from IRavenWriter
Keep Execute and ExecutionIntervalInSeconds in IRavenWriter
Make IRavenWriter have Func<DateTime> and use that in your writer
Move Initialize to IRavenWriter<T>
Use a factory to initialise the Func according to the type and expression:
For example:
public class MyDateTime
{
public DateTime This { get; set; }
}
public static Func<DateTime> GetFunk<T>(Expression<Func<T, DateTime>> timeOrderByFunc, T t)
{
return () => timeOrderByFunc.Compile()(t);
}
And you use:
GetFunk<MyDateTime>(x => x.This, new MyDateTime(){This = DateTime.Now});
It's not really hard to turn run-time Type into compile-time generic Type parameter. Just introduce new interface for creating/initializing your objects:
interface IRawenWriterFactory
{
object Create();
}
class RawenWriterFactory<T> : IRawenWriterFactory
{
public object Create()
{
Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime;
var ravenWriter = new RavenWriterBase<T>();
ravenWriter.Initialize(60, func);
return ravenWriter;
}
}
Now just create RawenWriterFactory with dataEntityType just like you've created ravenWriter and use it via non-generic IRavenWriterFactory interface.
However, there could be simpler solutions if you'll change your design. E.g. if you turn Initialize method into constructor you'll be able to pass func as Activator.CreateInstance parameter and you wouldn't need to use generic interface for initialization at all.

Is it possible to using Type Inference for the first parameter and specify another type

This is a simple contrived example, but hopefully will illustrate my query.
public class Test
{
public string Name = "test";
}
public static class Ext
{
public static Test ConvertToTest<T1>(this T1 source)
{
return new Test();
}
public static T2 Convert<T1,T2>(this T1 source) where T2 : new()
{
return new T2();
}
}
ConvertToTest only needs one Type, so the following compile
Ext.ConvertToTest<string>("hello");
"hello".ConvertToTest();
The last uses type-interfence and this means it also works with anonymous classes, eg
var anon = (new { Name = "test" }) ;
anon.ConvertToTest();
However this is hardcoded to always use the class Test, whereas I want to be able to specify the type as in the second method
I can write
Ext.Convert<string, Test>("hello");
and this compiles, because I know both types at compile time, but I can't use it with anonymous classes, and I can't find a way of using type-inference plus the extra Type
It would be nice if I could do something like
anon.Convert<,Test>() ;
and the compiler would know to use inference for the first type (which isn't specified) and use Test as the second type.
Is there any way around this issue?
You can't do what you're asking on a single method, but if you're clever and willing to define a couple of different classes you should be able to make syntax like this possible:
var test = Ext.Convert("hello").To<Test>();
Just make Convert be based on a single generic type, and have it return a generic type based on that:
public Converter<T> Convert<T>(T source)
{
return new Converter<T>(source);
}
Then add a method to the type it returns which serves as a basic wrapper for your original method:
public class Converter<T>
{
T _source;
internal Converter(T source)
{
_source = source;
}
public T2 To<T2>()
{
return Ext.Convert<T, T2>(_source);
}
}
There is a way to do what you want. You use a template pattern - it's a little bit of a kludge but it allows you to infer both types. It can also be use to infer anonymous types.
Here it is:
public static T2 Convert<T1,T2>(this T1 source, Func<T2> template)
where T2 : new()
{
return new T2();
}
You can call it like this:
var anon = (new { Name = "test" }) ;
anon.Convert(() => new Test());
Which isn't too far from your pseudo-code.

Categories

Resources