I looked at https://stackoverflow.com/a/5174773/787958 and the method resolution is not working as expected in my instance.
I have JSON coming into a method that I want to create a typed object from and then validate it.
var type = Type.GetType($"{Namespace.Models}.{typeName.FirstCharToUpper()}");
var model = JsonConvert.DeserializeObject(json, type);
var validator = new Validator();
var isValid = await validator.ValidateAsync(model);
The Validator class looks as such:
public class Validator : IValidator
{
public Task<Boolean> ValidateAsync(Object model) { return Task.FromResult(true); }
public Task<Boolean> ValidateAsync(User user)
{
if (user.Id == null || user.Id == Guid.Empty)
return Task.FromResult(false);
if (String.IsNullOrWhiteSpace(user.Name))
return Task.FromResult(false);
return Task.FromResult(true);
}
}
Even though at runtime, type is User, it does not call the ValidateAsync(User user) method, instead it calls ValidateAsync(Object model) method.
But, if the type is not dynamic at compile time and instead I do:
var model = JsonConvert.DeserializeObject<User>(json);
It properly calls the ValidateAsync(User user) method.
Is there a proper way to have a dynamic type at compile time, but known at runtime, and have it call the expected "more specific" method?
UPDATE
Having any "future coder" add to the switch statement was not too much of an ask imo, since they would be in that class adding their new ValidateAsync(NewModel model) method anyways. Utilizing dynamic was more along the lines of how I would like the code to be as it would not bloat the code with a possibly larger and larger switch statement. But, I was worried about performance impact. So I ran a Postman runner 250 times with the switch statement (just User or default) and 250 times with dynamic. The differences in performance was negligible.
Average response time with switch: 2.668ms
Average response time with dynamic: 2.816ms
So, I'm going to go with the dynamic solution. Thanks!
Overload resolution happens at the compile time, not in the runtime. model created by var model = JsonConvert.DeserializeObject(json, type); will be of object type so compiler will expectedly select ValidateAsync(Object model) overload.
You may try using dynamic for late bound (runtime) resolution:
dynamic model = JsonConvert.DeserializeObject(json, type);
var validator = new Validator();
var isValid = await validator.ValidateAsync(model);
But note that it comes with some performance cost.
Another option is type testing and casting. For example with pattern matching can look like this:
var isValid = model switch
{
User user => await validator.ValidateAsync(user),
_ => await validator.ValidateAsync(model)
}
The type of method resolution you're thinking of happens at compile time.
If you want to resolve the method at run time you have to write the code for it yourself, e.g.
public Task<Boolean> ValidateAsync(Object model)
{
return (model is User) ? ValidateAsync((User)model) : Task.FromResult(true);
}
Related
I receive data from a DB. There will be only one model at a time which I call currentModel from now on. The type of model received must be determined at runtime. Therefore, I implemented an Interface for the models IDataModel. Each possible model implements IDataModel. There is a variable which holds the currentModel. In order to make it generic I defined it as IDataModel. Here is the code so far.
public async Task<List<T>> LoadData<T, U>(string sql, U parameters, string connectionString)
{
using (IDbConnection connection = new SqlConnection(connectionString))
{
var rows = await connection.QueryAsync<T>(sql, parameters);
return rows.ToList();
}
}
private IDataModel currentModel;
private List<IDataModel> queryResult;
if (someCondition)
{
currentModel = newSpecificModel();
sql = someQuery;
}
else ....
queryResult = await _data.LoadData<IDataModel, dynamic>(sql, new {}, config.GetConnectionString("default"));
if (queryResult.Count == 1)
{
currentModel= queryResult.First();
}
else
{
// Do error handling here if more than one row is returned from the query
}
Now when I try to access some property I get an error: IDataModel does not contain a definition for someProperty
currentModel.someProperty
How do I determine the current implementation at runtime?
I mean I could create a variable for each possible model. But is there a more elegant way?
EDIT
Nailed the problem down to that this wont work:
List<Interface> = List<Implementation>
See this post.
Whats an approach to solve this?
Have a look at the curiously recurring template pattern; it is useful for creating child objects with the right type.
Maybe also look at this discussion.
I want to mock a service to always return a default object.
I tried this but it still always return null:
var service = new Mock<MyService>();
service.SetReturnsDefault(Task.FromResult(new ServiceResult<object>
{
Status = ResultStatus.OK,
Value = null
}));
The methods are async and return Task<IServiceResult<object>> where object can be any object (also a collection of objects).
ServiceResult implement the IServiceResult interface.
Why is it not working? I would like to avoid setup every method...
Thanks for your help!
EDIT:
I use for example a method like this but it result is always null instead of the default ServiceResult:
var result = await _service.GetEntityAssetUsagesAsync(EntityTypeEnum.Radio, radio.MediaChannelId);
Here is (a piece of) my interface:
Task<IServiceResult<List<EntityAssetUsageDto>>> GetEntityAssetUsagesAsync(EntityTypeEnum entityType, int entityId);
Task<IServiceResult<List<AssetDto>>> GetAssetsAsync(List<long> assetIds, bool withoutException = false);
[INTRO]
I know there are about a zillion QA about generics and reflections everywhere, but it's becoming a blackhole to me, and I'm only getting more lost the more I read!!
What i need to do is simple, and I'm amazed that it hasn't been addressed before.
[SAMPLE] Consider the following snippit:
public async Task<string> generateJsonSchema(string model)
{
try
{
string modelName = "Models." + model;
Type t = Type.GetType(modelName, false);
JsonSchema4 schema = await JsonSchema4.FromTypeAsync<t>();
return schema.ToJson();
}
catch (Exception ex)
{
Logger.WriteToLogFile(ex.ToString(), "exception");
return "";
}
}
[PROBLEM] Now the main problem is that variable t is evaluated at runtime, thus, JsonSchema4.FromTypeAsync<t>() throws the error 't' is a variable but is used like a type when trying to build compile time
Whoever used JsonSchema4 will understand what I'm trying to achieve here.
Instead of creating a generate function for each of my models, or make a switch/if-else logic,
[QUESTION]
How to make it receive the model name as a string parameter, and convert the string-model-name to model-type and pass it to jSonSchema4 method.
The problem here is that, as you say, t is evaluated as runtime.
I also ran into this Problem and solved it by creating a MethodInfo of the method I wanted to invoke, in your case JsonSchema4.FromTypeAsync<t>().
So basically this is want may fix the problem:
var methodInfo = typeof(JsonSchema4).GetMethod("FromTypeAsync", new Type[] { }); //Get the "normal method info", the overload without parameters
var methodInfoWithType = methodInfo.MakeGenericMethod(t); //now you have a method with your desired parameter t as TypeParameter
Task<JsonSchema4> task = methodInfoWithType.Invoke(null, null) as Task<JsonSchema4>; //now you can cast the result from invoke as Task to keep the Async-Await functionality
var schema = await task;
return schema.ToJson();
I'm actually using this switch and wanted to refactor it since it can grow significantly depending in my application's uses.
switch (something)
{
case "emisores":
return await StampEmisor(id);
case "tipodocumento":
return await StampTipoDocumento(id);
case "plantillas":
return await StampPlantilla(id);
default:
return BadApiRequest("blabla was not found.");
}
I need to:
1.- Return values
2.- Pass parameters
3.- Call async methods
I tried following this solution but those 3 conditions aren't applying. How could I perform this?
Many thanks.
In order to return values (1st requirement) you will have to convert the Action inside the Dictionary to Function:
new Dictionary<string, Func<>>()
Since that implicitly makes this returning TResult, you will have to specify what you're returning as the last parameter inside the Func definition itself, and specifying in first place the parameter you're passing (2nd requirement).
Which gets finally into
var stamps = new Dictionary<string, Func<Guid, Task<HttpResponseMessage>>>()
{
{ "emisores", new Func<Guid,Task<HttpResponseMessage>>(StampEmisor) },
{ "tipodocumento",new Func<Guid,Task<HttpResponseMessage>>(StampTipoDocumento)},
{ "plantillas", new Func<Guid,Task<HttpResponseMessage>>(StampPlantilla)},
{ "reglas", new Func<Guid, Task<HttpResponseMessage>>(StampRegla) }
};
Now, in order to call it awaitedly (3rd condition) just call the .Invoke(id) with the await statement. In this case, return await because we want to return the provided value:
if (stamps.ContainsKey(entity))
return await stamps[entity].Invoke(id);
I have three projects
MVC Web application
Service application which is kind of two layers business/repository
Entity framework (all EF configuration lives here)
MVC references > service
Service references > EF
I have these three methods currently that do some work.
public bool StoreUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
public bool RemoveUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
public bool CommitUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
I call these three methods from my controller using these interfaces which delegate to the work methods above:
Boolean StoreUpload(UploadInformation information);
Boolean RemoveUpload(UploadInformation information);
Boolean CommitStoredDocuments(UploadInformation information);
Based on a condition from UploadTypes enumeration in a switch I call the correct work method. I do this because I don't want my mvc project to have access to the EF database types otherwise I know someone is going to start querying data from all over the application. I use these switch statements for all interfaced methods:
public bool StoreUpload(UploadInformation information)
{
switch (information.Type)
{
case UploadTypes.AutoIncident:
return RemoveUpload<AutoIncident>(information);
case UploadTypes.Incident:
return RemoveUpload<IncidentInjury>(information);
case UploadTypes.Inspection:
return RemoveUpload<Inspection>(information);
case UploadTypes.OtherIncident:
return RemoveUpload<OtherIncident>(information);
default:
return false;
}
}
public bool RemoveUpload(UploadInformation information) { ... }
public bool CommitStoredUpload(UploadInformation information) { ... }
This method might shed a little light on what the types parameters are being used for. I am updating tables in a generic way using EF.
private bool CommitStoredDocuments<T>(UploadInformation information) where T : class, IUploadEntity
{
var uploads = GetStoredUploads(information.UniqueId);
var entity = db.Set<T>().Include(e => e.Uploads)
.Single(e => e.UniqueId == information.UniqueId);
entity.Uploads.AddRange(uploads);
...
}
It would be nice to be able to pass the work method which requires a type parameter as a delegate to the switch work method calls.
public bool DoSomeWork(delegateMethod, information) {
switch(information.Type) {
case UploadTypes.AutoInciden:
return delegateMethod<AutoIncident>(information);
...
}
}
Can this be done?
Also, I had trouble constructing a good title for this question so please comment if these is a better way to describe the challenge.
It cannot be done directly due to several reasons.
First of all, as you probably noticed, delegateMethod<FooBar>(information) simply does not compile. This is because in your example the delegateMethod is a local variable (method parameter actually, but still a variable), and you cannot apply "type arguments" <FooBar> to a variable - you can apply them only on an identifier that indicates a (generic) type or a (generic) method.
Second reason is more interesting. When you pass a method as a delegate, the delegate actually catches the whole method signature, including all parameter types.
void Blah<T>(UploadInformation information){ ... }
var one = new Action<int>(Blah); // -> Blah<int>
var two = new Action<float>(Blah); // -> Blah<float>
var thr = new Action<andsoon>(Blah); // -> Blah<andsoon>
MagicDoSomeWork(one, ...); // these all
MagicDoSomeWork(two, ...); // delegates are already bound
MagicDoSomeWork(thr, ...); // and remember their concrete T
You need to actually specify the type for the Action so a proper version of generic method will be picked from a general description called Blah. These delegates are bound to concrete versions of the method and will accept only that types. These delegates are 'closed' in terms of their type arguments. Using normal ways, the MagicDoSomeWork will simply have no way of altering the T which these delegates already have remembered.
That two things are a kind of show stoppers, since by normal code only, you cannot write things like
var nope1 = new Action(Blah); // ctor for Action NEEDS type parameter
since Action constructor simply requires a type parameter. And once you pass any, it will lock the Blah type arguments
Also you cannot use open delegates:
var nope1 = new Action<>(Blah); // can't use empty <> in this context :(
since new operator requires a full type to create an object.
However, with a bit of reflection voodoo, it is possible to analyze and build a generic type or a generic method dynamically.
// first, build the delegate in a normal way
// and pick anything as the type parameters
// we will later replace them
var delegateWithNoType = new Action<object>(Blah);
// delegate has captured the methodinfo,
// but uses a stub type parameter - it's useless to call it
// but it REMEMBERS the method!
// .... pass the delegate around
// later, elsewhere, determine the type you want to use
Type myRealArgument;
switch(..oversomething..)
{
default: throw new NotImplemented("Ooops");
case ...: myRealArgument = typeof(UploadTypes.AutoIncident); break;
...
}
// look at the delegate definition
var minfo = delegateWithNoType.Method;
var target = delegateWithNoType.Target; // probably NULL since you cross layers
var gdef = minfo.GetGenericDefinition();
var newinfo = gdef.MakeGenericMethod( myRealArgument );
// now you have a new MethodInfo object that is bound to Blah method
// using the 'real argument' type as first generic parameter
// By using the new methodinfo and original target, you could now build
// an updated delegate object and use it instead the original "untyped" one
// That would be a NEW delegate object. You can't modify the original one.
// ...but since you want to call the method, why don't use the methodinfo
UploadInformation upinfo = ... ;
newinfo.Invoke(target, new object[] { upinfo });
// -> will call Blah<UploadTypes.AutoInciden>(upinfo)
word of warning: this is a sketch to show you how the delegate.Method/Target and methodinfo and getgenericdefinition and makegenericmethod work. I wrote it from memory, never compiled, never ran. It can contain minor typos, overlooked things and invisible rainbow unicorns. I didn't noticed any. Probably because they were invisible.
You can do it like this
public bool Invoke(EntityType entityType, ActionType action, Object[] arguments)
{
var actionType = Enum.GetName(typeof(ActionType), action);
var type = GetType();
var method = type.GetMethods().Single(m => m.IsGenericMethod && m.Name == actionType);
switch (entityType)
{
case EntityType.IncidentInjury:
var genericMethod = method.MakeGenericMethod(typeof(IncidentInjury));
return (bool)genericMethod.Invoke(this, arguments);
default:
return false;
}
}
The enum will just be a list of methods that I want to invoke this way and I create a base class for my services so I don't have to pass the instance to the Invoke method.
Instead of using delegates, consider using an interface (or abstract class). This way, your methods can retain their generic nature.
For example, if you create an interface like:
interface IUploadAction
{
bool Perform<T>(UploadInformation information)
where T : class, IUploadEntity;
}
Note that the T is not exposed in the type, it's only on the method. This is the key part.
Now you can implement this for your database methods:
class CommitStoredDocuments : IUploadAction
{
public bool Perform<T>(UploadInformation information)
where T : class, IUploadEntity
{
var uploads = GetStoredUploads(information.UniqueId);
var entity = db.Set<T>().Include(e => e.Uploads)
.Single(e => e.UniqueId == information.UniqueId);
entity.Uploads.AddRange(uploads);
//...
}
}
Your switching/dispatching method can look like this:
public bool DoAction(IUploadAction action, UploadInformation information)
{
switch (information.Type)
{
case UploadTypes.AutoIncident:
return action.Perform<AutoIncident>(information);
case UploadTypes.Incident:
return action.Perform<IncidentInjury>(information);
case UploadTypes.Inspection:
return action.Perform<Inspection>(information);
case UploadTypes.OtherIncident:
return action.Perform<OtherIncident>(information);
default:
return false;
}
}
And then you can write something like:
IUploadAction storeUpload;
public bool StoreUpload(UploadInformation information) => DoAction(storeUpload, information);