Generics & static classes. Implement query helper method - c#

Currently we implement a mapping service like this (the service uses automapper, and we make use of the projection feature on it for this part)
// Injected
// IGenericRepository<Entity> entityRepo
var query = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1);
var result = this.mappingService
.Map<Entity, EntityDto>(query)
.FirstOrDefault();
I'd like to create an extension that would allow me to do the following
var result = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1).Map<EntityDto>() <--- Entity inferred from repo type
.FirstOrDefault();
My current attempt:
public static class IQueryableExtensions
{
private static IMappingService mappingService;
// will need to be called in app initialization
public static void InitialiseMapper(IMappingService service)
{
mappingService = service;
}
public static IEnumerable<TDto> Map<TAttribute, TDto>(this IQueryable<TAttribute> value)
where TDto : class
where TAttribute : IEntity
{
return mappingService.Map<TAttribute, TDto>(value);
}
}
Thus currently my implementation would look like this.
var result = this.entityRepo
.FindAll(a => a.Id == someId)
.Take(1).Map<Entity,EntityDto>()
.FirstOrDefault();
Questions:
1) How would i go about inferring the entity type from the IQueryable object
2) I realize i cant create a constructor that takes parameters, when creating a static class. Is the way i init the mapper the best/only way?

I tried that with reflection. The constraints are only for demo. If you want to call the reflection code multiple times be sure to cache the final methodinfo.
void Main()
{
var a = new Entity[] {new Entity { name = "a"},new Entity { name = "b"}};
Console.WriteLine(a.Take(1).Map<EntityDto>());
}
public class Entity
{
public string name;
}
public class EntityDto
{
public string dtoname;
}
public static class EntityExtensions
{
public static IEnumerable<U> Map<T,U>(this IEnumerable<T> e) where T: Entity where U: EntityDto, new()
{
foreach(var a in e)
{
yield return new U() { dtoname = a.name };
}
}
public static IEnumerable<U> Map<U>(this IEnumerable<object> e)
{
var method = typeof(EntityExtensions).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "Map" && m.GetGenericArguments().Length == 2)
.Single();
method = method.MakeGenericMethod(e.GetType().GetGenericArguments()[0], typeof(U));
return method.Invoke(null, new object[] { e}) as IEnumerable<U>;
}
}

1) Currently, you simply can't do that in C#. The type inference is not good enough. You can either specify all type parameters or none of them.
Edit: If you really want the version with a single parameter, you have to delete the second type parameter, type the parameter as non-generic IQueryable and deal with it. One way of doing that would be to determine the generic IQueryable<T> type at runtime. However, this requires reflection. In the case of IQueryable, you can also use the query provider to get around the reflection.
2) You can use a static type constructor.
public static class MyExtensions {
static MyExtensions() {
//initialization goes here
}
}
This type constructor is even called thread-safe. However, if you manage to throw an exception here, you cannot access the MyExtensionsclass!

Related

How to register a function (eg. to a class)?

Context
I am writing an app which can call functions at runtime with the given function name.
The following setup could be an example:
internal class Caller
{
public static Dictionary<string, Func<object, object>> reg = new Dictionary<string, Func<object, object>>();
static Caller()
{
reg.Add("example1", Funcs.example1);
reg.Add("example2", Funcs.example2);
}
public object Call(string name, object obj)
{
return reg[name](obj);
}
}
internal static class Funcs
{
public static object example1(object obj)
{
// do sth
return obj;
}
public static object example2(object obj)
{
// do sth else
return obj;
}
}
Problem
The Problem with this is that my code isn't expandable. It would be difficult to register more functions at runtime/in another assembly, and it is a lot of typing for each function.
Coming from Python, I am used to using #decorators. They could be applied on every function I want to register, and then it would register it automatically.
In c# we have [Attributes], so I am thinking about giving each function a [CustomAttribute] and in my static Caller() I loop through every assembly, every static class in the assembly, and then register all functions with the [CustomAttribute].
I don't know whether this is ok to do from a design and performance standpoint.
I know of [HttpGet] from ASP.NET, what approach do they use? (Couldn't find it in the source). Is there perhaps a design pattern I am missing?
You can try obtaining all the methods via Reflection, e.g.
Let's obtain all public static methods from Funcs such that return object and take exactly one argument of type object (you can add your custom Where to apply more filters and narrow down the methods which should be registered):
using System.Linq;
using System.Reflection;
...
internal class Caller {
public static readonly IReadOnlyDictionary<string, Func<object, object>> reg = typeof(Funcs)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(method => method.ReturnType == typeof(object))
.Where(method => method.GetParameters().Length == 1 && method
.GetParameters()
.All(prm => prm.ParameterType == typeof(object)))
.ToDictionary(method => method.Name,
method => new Func<object, object>(arg => method.Invoke(null, new[] { arg })));
public object Call(string name, object obj) {
return reg[name](obj);
}
}
Usage:
Caller caller = new Caller();
...
var result = caller.Call("example1", "Hello World!");
If you want to use an Attribute to mark invokable methods #Dmitry Bychenkos answer will already get you most of the way there.
Just define an attribute
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
class RuntimeInvokable : Attribute { }
And some syntax sugar to help with the reflection (I've intentionally left the parameter count and return type checks out to keep it shorter, see Dmitrys answer for that)
static class ExtensionMethods
{
public static Func<object, object?> ToFunc(this MethodInfo method)
{
return new Func<object, object?>(o => method.Invoke(null, new[] { o }));
}
public static IEnumerable<MethodInfo> GetRuntimeInvokableMethods(this Type type)
{
return type
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.GetCustomAttribute<RuntimeInvokable>() is not null);
}
}
I think using a Dictionary is fine, so you won't have to use reflection on every call. I'd rather use a singleton instead of a static caller but that´s optional
class Caller
{
Dictionary<string, Func<object, object?>> reg = new();
public Caller()
{
reg = typeof(*someType*)
.GetRuntimeInvokableMethods()
.ToDictionary(x => x.Name, x => x.ToFunc());
}
public object? Call(string name, object obj)
{
return reg[name](obj);
}
}
If you want to not be limited to methods of a single class, you can allow the attribute to be used for classes as well and check all types of an assembly
public static IEnumerable<Type> GetRuntimeInvokableTypes(this Assembly assembly)
{
return assembly
.GetTypes()
.Where(x => x.GetCustomAttribute<RuntimeInvokable>() is not null);
}
And change the Caller constructor to
reg = typeof(Caller)
.Assembly
.GetRuntimeInvokableTypes()
.SelectMany(x => x.GetRuntimeInvokableMethods())
.ToDictionary(x => x.Name, x => x.ToFunc());

Converting c# methods to a generic method

How can I convert these two ConvertDtoListToAddresses and ConvertDtoListToDocuments C# methods to a generic? I've tried passing in two generic type variables, but when I get down to 'Add' in the loop I get stuck on various errors. Converting from a DTO to its respective DBO is done in the constructor of the DBO, which I think is part of the problem.
private void ConvertDtoToPerson(PersonDTO dto)
{
Id = dto.Id;
Fname = dto.FirstName;
Mname = dto.MiddleName;
Lname = dto.LastName;
Suffix = dto.Suffix;
Maiden = dto.MaidenName;
Addresses = ConvertDtoListToAddresses(dto.AddressesDto); // want to convert to generic
Documents = ConvertDtoListToDocuments(dto.DocumentsDto); // want to convert to generic
}
private static ICollection<Address>? ConvertDtoListToAddresses(ICollection<AddressDTO>? addressesDto)
{
if (addressesDto is not null && addressesDto.Any())
{
ICollection<Address> addys = new List<Address>();
foreach (AddressDTO dto in addressesDto)
{
// Converts from dto in constructor
addys.Add(new Address(dto));
}
return addys;
}
return null;
}
private static ICollection<Document>? ConvertDtoListToDocuments(ICollection<DocumentDTO>? documentsDto)
{
if (documentsDto is not null && documentsDto.Any())
{
ICollection<Document> docs = new List<Document>();
foreach (DocumentDTO dto in documentsDto)
{
// Converts from dto in constructor
docs.Add(new Document(dto));
}
return docs;
}
return null;
}
Here is what I tried:
Addresses = ConvertDtoListToType<Address, AddressDTO>(dto.AddressesDto);
private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection)
{
if (dtoCollection is not null && dtoCollection.Any())
{
ICollection<T> tList = new List<T>();
foreach (D dto in dtoCollection)
{
tList.Add(new T(dto)); // <-- This is where I'm having trouble
}
return tList;
}
return null;
}
Use of a Func<D, T> factory parameter would sort this out.
private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection, Func<D, T> factory)
{
if (dtoCollection is not null && dtoCollection.Any())
{
ICollection<T> tList = new List<T>();
foreach (D dto in dtoCollection)
{
tList.Add(factory(dto));
}
return tList;
}
return null;
}
Do keep in mind that that is almost the semantic equivalent of this:
private static ICollection<T>? ConvertDtoListToType<T, D>(ICollection<D>? dtoCollection, Func<D, T> factory)
=> dtoCollection?.Select(d => factory(d))?.ToList();
I'd question the idea that an empty dtoCollection should return a null final collection anyway. This is probably a better implementation.
So, having said that, your original method offers very little functionality benefit. It's code for code's sake. A simple Select/ToList pair keeps your code simple.
In any case, you can provide a static method off of Address and Document to provide the Func<D, T> that you need.
public class Address
{
AddressDTO dto;
public static Address CreateFromDto(AddressDTO dto)
=> new Address(dto);
public Address(AddressDTO dto)
{
this.dto = dto;
}
}
Now, calling it is like this:
var addresses = ConvertDtoListToType(addressDtos, Address.CreateFromDto);
Or:
var addresses = addressDtos?.Select(Address.CreateFromDto)?.ToList();
What you need is to be able to provide a constraint on the Type T to say that it has a constructor that takes a parameter of type D. Something like this:
private static ICollection<T>? ConvertDtoListToType<T, D>(
ICollection<D>? dtoCollection) where T : new(D)
{}
But this does not exist in C#. The workaround is to provide a factory method to create your type T given a type D. i.e. Something like:
private static ICollection<T>? ConvertDtoListToType<T, D>(
ICollection<D>? dtoCollection, Func<D, T> factory)
{
// Use factory(dto), instead of new T(dto)
}
But as #Zee says, you should have a look at Automapper, which can convert between types of collections.

Type.GetMethod() for polymorphic method (both generic and non-generic)

I am currently creating a custom way of deep-copying my objects. I use a static class for this functionality.
public static class CopyServer
{
public static int CopyDeep(int original)
{
return original;
}
//not shown: same for all other value types I use (long, float,...)
public static T CopyDeep<T>(T original) where T: ICopyAble
{
if (original == null)
return default;
if (original is ICopyAutofields)
return CopyAutofields(original);
return (T)original.CopyDeep();
}
private static T CopyAutofields<T>(T original)
{
Delegate del;
if (!_copyFunctions.TryGetValue(typeof(T), out del))
{
//not shown: Building expression for parameter etc.
foreach (var fieldInfo in typeof(T).GetFields())
{
//not shown: checking options set by custom attributes
MethodInfo methodInfo = typeof(CopyServer).GetMethod("CopyDeep", new[] { fieldInfo.FieldType });
//I can't remove the second param without getting an AmbiguousMatchException
if (methodInfo == null)
{
throw new Exception($"CopyDeep not defined for type {fieldInfo.FieldType}");
}
if (methodInfo.IsGenericMethod)
methodInfo = methodInfo.MakeGenericMethod(fieldInfo.FieldType);
Expression call = Expression.Call(methodInfo, readValue);
//not shown: Assign Expression
}
//not shown: return Expression and compiling
}
return ((Func<T, T>)del)(original);
}
}
I use T CopyAutofields<T> to build functions (by building and compiling Expression Trees) so I don't have to create copy-functions for each and every class I want to copy by hand. I control the copy-behaviour with Custom Attributes (I left this part in the code above since it is not relevant for my problem).
The code works fine as long as long as only fields with types for which a non-generic function exists are used. But it is not able to retrieve my generic function T CopyDeep<T>.
Example:
//This works:
public class Manager : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
}
//This doesn't
//Meaning: typeof(CopyServer).GetMethod("copyDeep", new[] { fieldInfo.FieldType });
//in T copyAutofields<T> returns null for the Manager-field and my exception gets thrown
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
}
//This is what I was using before I started using the ICopyAutofields.
//This approach works, but its' too much too write since my classes usually
//have way more than three fields and I occasionally forget to update
//copyDeep()-function if I add new ones.
public class Employee : ICopyAble,ICopyAutofields
{
public string FirstName;
public string LastName;
public Manager Manager;
public IModable CopyDeep()
{
var result = new Employee();
result.FirstName = CopyServer.copyDeep(FirstName);
result.LastName= CopyServer.copyDeep(LastName);
result.Manager= CopyServer.copyDeep(Manager);
return result;
}
}
Long story short: I need a way of getting a matching function for a type T if both generic and non-generic functions with the right name exist.
In .NET 4.7.1 you need to use method GetMethods and filter the results:
class MyClass
{
public T M<T>(T t) { return default(T); }
public int M(int t) { return 0; }
}
var m = typeof(MyClass).GetMethod("M", new[] { typeof(string) }); // null
var m1 = typeof(MyClass).GetMethods()
.Where(mi => mi.Name == "M" && mi.GetGenericArguments().Any())
.First(); // returns generic method
In .NET Standard 2.1 (and .NET Core since 2.1) there is another way to resolve generic type arguments - Type.MakeGenericMethodParameter, like you can see it in this answer.
Also as workaround you can move your copyAutofields<T> method to generic class like CopyAutoFieldServer<T>:
public static class CopyAutoFieldServer<T>
{
public static T copyAutofields(T original) { ... }
}

one generic class create generic extension with expression<T,bool> method

My code is as follows:
public partial class WhereHelper<T1> { }
public static partial class WhereHelperExtension
{
public static T Where<T,T1>(this T t, Expression<Func<T1,bool>> where) where T : WhereHelper<T1>
{
//do something....
return t;
}
}
public class Test
{
public void Main()
{
WhereHelper<DateTime> dt = new WhereHelper<DateTime>();
dt.Where(t => t.Year == 2016);//this is error
dt.Where<WhereHelper<DateTime>, DateTime>(t => t.Year == 2016);//this is success
}
}
Extension method I want to be like this:
WhereHelper<DateTime> dt = new WhereHelper<DateTime>();
dt.Where(t => t.Year == 2016);//this is error
how to create generic extension with Expression method.
Visual Studio does not recognize the "Where" extension methods.
In C#, if you need to provide any generic argument, you must provide them all. where constraints do not provide hints to the type resolver, and so it's impossible to decide what T1 is.
Change your signature to the following:
public static WhereHelper<T> Where<T>(this WhereHelper<T> t, Expression<Func<T,bool>> where)
{
return t;
}
Here, we know exactly what T, purely from the first argument, and so we do not have to explicitly specific the arguments.

Generic conversion method throw InvalidCastException

I want to implement same simple generic conversion method but on runtime I am getting an error.
So the scenario is quite simple. I have same service that return me list of items of type External. I have my own WrapperExternal class that simply wrap this class and expose some additional functionality to it. I have some another set of classes that inherit from WrapExternal and add different functionalities.
I want to create generic method that accept list of External list items and return list of items of specified type.
My application code:
static void Main(string[] args)
{
var items = GetItemsFromServer();
var converted = ConvertItems<SubWrapperExternal>(items).ToList();
}
public static IEnumerable<T> ConvertItems<T>(IEnumerable<External> externalItems) where T : WrapperExternal
{
return externalItems
.Where( item => true)
.Select(item => (T)item);
}
When you try to run this code you will get exception in line (T)item:
An unhandled exception of type 'System.InvalidCastException' occurred in ConsoleApplication1.exe
Additional information:
Unable to cast object of type 'ConsoleApplication1.WrapperExternal' to type 'ConsoleApplication1.SubWrapperExternal'.
Do you know how can I make it to works?
Test application code:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var items = GetItemsFromServer();
var converted = ConvertItems<SubWrapperExternal>(items).ToList();
}
private static List<External> GetItemsFromServer()
{
return new List<External>
{
new External{Name = "A"},
new External{Name = "B"},
new External{Name = "C"},
};
}
public static IEnumerable<T> ConvertItems<T>(IEnumerable<External> externalItems) where T : WrapperExternal
{
return externalItems
.Where( item => true)
.Select(item => (T)item);
}
}
class External
{
public string Name { get; set; }
}
class WrapperExternal
{
public External External { get; private set; }
public WrapperExternal(External external)
{
External = external;
}
public static explicit operator WrapperExternal(External item)
{
return item != null ? new WrapperExternal(item) : null;
}
public static implicit operator External(WrapperExternal item)
{
return item != null ? item.External : null;
}
}
class SubWrapperExternal : WrapperExternal
{
public SubWrapperExternal(External external)
: base(external)
{
}
public static explicit operator SubWrapperExternal(External item)
{
return item != null ? new SubWrapperExternal(item) : null;
}
public static implicit operator External(SubWrapperExternal item)
{
return item != null ? item.External : null;
}
}
}
Conversion operators are a faff to use with generics - generics don't support any static operator overloads. Because of this, the (T) cast is performing a non-converting type check (generics need to use the same IL for every possible T, remember) - a basic castclass.
The only "simple" way of doing what you want is to cheat with dynamic:
return externalItems.Select(item => (T)(dynamic)item);
Since the C#-specific dynamic provider knows all the common rules of C#, it knows about conversion operators, and will apply them on-demand. There is a slight performance cost associated with this, but it isn't as bad as it looks at first glance, as the strategy is cached (as IL) once per type - it doesn't perform per-item reflection.

Categories