I have a method that performs the same function on different objects passed in:
public ??? DoThings(??? inputObject)
{
//do things
if(condition)
inputObject.Status = "error";
}
Objects are of the following class:
public class BaseResponse<T>
{
public string Status { get; set; }
public T Data { get; set; }
public static BaseResponse<T> FromJson(string data)
{
return JsonConvert.DeserializeObject<BaseResponse<T>>(data, JsonHelper.JsonSettings);
}
}
At the end of the method I may need to change the object's Status to an error. How can this be achieved? I have tried to pass in object inputObject. but that of course doesn't work.
Make the method generic:
public void DoThings<T>(BaseResponse<T> inputObject)
{
// do things
if (condition) inputObject.Status = "error";
}
Then you can pass any BaseResponse<T> object:
var baseResponse = BaseResponse<SomeDataType>.FromJson(jsonString);
DoThings(baseResponse); // T can be inferred from baseResponse
Related
I have an idea, but I don't understand how to do it.
I've created an abstract class AJsonSerializer. And there I want to Serialize and Deserialize classes.
public abstract class AJsonSerializer {
public string ToJson() {
return JsonConvert.SerializeObject(this);
}
public T FromJson<T>(string jsonString) where T : class {
return JsonConvert.DeserializeObject<T>(jsonString);
}
}
I have a class User where I inherited from my abstract class:
public class User : AJsonSerializer {
public string PublicKey { get; set; }
public int User_ID { get; set; }
}
And now I can do like that
internal static void Get_UserData(string username, ref User user) {
if (ReadFromCache(username, out string value)) {
user = user.FromJson<User>(value);
} else {
DataAccess.Get_UserData(username, out string user_public_key, out int id_user);
user.PublicKey = user_public_key;
user.User_ID = id_user;
value = user.ToJson();
SaveToCashe(username, value);
}
}
This row looks ugly: user = user.FromJson<User>(value);
I want to do it like that: user.FromJson(value);
I know how I can do it in class User (example below), but I want to do it in abstract class and then this method will work for all my classes
Bad method how to solve it, just add initializer to class User like there:
public User(string jsonString) {
User user = JsonConvert.DeserializeObject<ApiUser>(jsonString);
PublicKey = user.PublicKey;
User_ID = user.User_ID;
}
Similar to Jerries answer, another option is just an extension method. You can have a constraint for T to be a AJsonSerializer to have it limited only to the subtypes of it. You can't override the extension method, but in your code you don't have it as virtual in the first place.
public static class SerializerExtensions {
public static T FromJson<T>(this T obj, string json) where T:AJsonSerializer {
JsonConvert.PopulateObject(json, obj);
return obj;
}
}
This way you won't need to implement passing of generic type throughout the inheritance chain.
But you need to initialize the value to access, so it would be:
var user = new User();
user.FromJson(jsonSTring);
or
var user = SerializerExtensions.FromJson(new User(), jsonString);
It's your decision what fits your use case better.
You could declare the generic type in your class definition
public class User : AJsonSerializer<User>
{
public string PublicKey { get; set; }
public int User_ID { get; set; }
}
public abstract class AJsonSerializer<T>
where T : class
{
public string ToJson() {
return JsonConvert.SerializeObject(this);
}
public static T FromJson(string jsonString) {
return JsonConvert.DeserializeObject<T>(jsonString);
}
}
Edit: and as Kara stated in his comment, your FromJson method can be static. So you can call it like
var user = User.FromJson(jsonString);
I'm still fairly new to programming and have been tasked with creating a WebHook consumer that takes in a raw JSON string, parses the JSON into an object, which will be passed into a handler for processing. The JSON is coming in like this:
{
"id":"1",
"created_at":"2017-09-19T20:41:23.093Z",
"type":"person.created",
"object":{
"id":"person1",
"created_at":"2017-09-19T20:41:23.076Z",
"updated_at":"2017-09-19T20:41:23.076Z",
"firstname":"First",
...
}
}
The inner object can be any object so I thought this would be a great opportunity to use generics and built my class as follows:
public class WebHookModel<T> where T : class, new()
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "object")]
public T Object { get; set; }
[JsonIgnore]
public string WebHookAction
{
get
{
return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last();
}
}
}
Then created the following interface:
public interface IWebHookModelFactory<T> where T : class, new()
{
WebHookModel<T> GetWebHookModel(string type, string jsonPayload);
}
What I'm failing to understand is how am I supposed to implement the Factory class without knowing what the type is at compile time?
Playing around with the Model a bit, I changed it to an abstract class with an abstract T object so that it could be defined by a derived class.
public abstract class WebHookModel<T> where T : class, new()
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "object")]
public abstract T Object { get; set; }
[JsonIgnore]
public string WebHookAction
{
get
{
return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last();
}
}
}
public PersonWebHookModel : WebHookModel<Person>
{
public override Person Object { get; set; }
}
But I still run into the same issue of trying to implement an interface in which I don't know the type at runtime. From what I've found online, this is an example of covariance, but I haven't found any articles that explain how to resolve this issue. Is it best to skip generics and create a massive
case statement?
public interface IWebHookFactory<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
TModel GetWebHookModel(string type, string jsonPayload);
}
I'm a bit partial to using the abstract class approach because it lets me define individual handlers based on which model I'm passing into my Service.
public interface IWebHookService<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
void CompleteAction(TModel webHookModel);
}
public abstract class BaseWebhookService<TModel, TJsonObject> : IWebHookService<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
public void CompleteAction(TModel webHookModel)
{
var self = this.GetType();
var bitWise = System.Reflection.BindingFlags.IgnoreCase
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.NonPublic;
var methodToCall = self.GetMethod(jsonObject.WebHookAction, bitWise);
methodToCall.Invoke(this, new[] { jsonObject });
}
protected abstract void Created(TModel webHookObject);
protected abstract void Updated(TModel webHookObject);
protected abstract void Destroyed(TModel webHookObject);
}
public class PersonWebHookService : BaseWebHookService<PersonWebHookModel, Person>
{
protected override void Created(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
protected override void Updated(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
protected override void Destroyed(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
}
Key points for the solution:
1. There needs to be some virtual call in there somewhere.
2. Somehow you need to map from your type tag in your JSON payload to your actual C# class.
IE, "person.created"," --> 'Person'.
If you control the serialization format, JSON.Net can inject its own type tag and do this for you. Assuming you can't go that route ...
So you'll need something like a Dictionary to contain the mapping.
Assuming your definitions is like:
abstract class WebhookPayload // Note this base class is not generic!
{
// Common base properties here
public abstract void DoWork();
}
abstract class PersonPayload : WebhookPayload
{
public override void DoWork()
{
// your derived impl here
}
}
And then you can deserialize like:
static Dictionary<string, Type> _map = new Dictionary<string, Type>
{
{ "person.created", typeof(PersonPayload)}
}; // Add more entries here
public static WebhookPayload Deserialize(string json)
{
// 1. only parse once!
var jobj = JObject.Parse(json);
// 2. get the c# type
var strType = jobj["type"].ToString();
Type type;
if (!_map.TryGetValue(strType, out type))
{
// Error! Unrecognized type
}
// 3. Now deserialize
var obj = (WebhookPayload) jobj.ToObject(type);
return obj;
}
I'm trying to accomplish some hacking & slashing and was wondering how to approach the following.
There are 2 interfaces defined:
public interface IBase
{
string Name { get; }
void Run();
}
public interface ISecondBase<T> : IEntityTask
{
Thing<T> Thing { get; }
}
Somewhere else I have a list of IBase.
This list is filled ISecondBase. I would like to be able to loop through the list of Base, but using some reflection tricks and hacks als be able to call Thing on the items. I know they're there, the compiler doesn't.
So I'd have to cast it to its concrete type at runtime, but this cast has to be dynamic, based on reflected information in the loop... So all type information is dynamic... I'm starting to think in circles :)
Since I know on beforehand that everything inside it is always of the SecondBase type, I decided to use the dynamic keyword and just let it resolve at runtime. This seems to me like an easy way out. Is there some best practice for these cases? Should I redesign, without loss of generality, and how?
foreach(var x in y)
{
dynamic melp = x;
melp.Thingy;
}
Where to start?
Edit: Perhaps some more code to make the example less contrived.
I have the base classes as mentioned. In real life they look like this:
public interface IEntityTask
{
string Name { get; }
void Run();
}
public interface IEntityTask<T> : IEntityTask
{
Task<T> Task { get; }
}
//Then there are classes that implement these:
public class CreateEntityTask<T> : IEntityTask<Guid>
{
public T Entity { get; private set; }
public Func<T, Guid> EntityMethod { get; private set; }
public Task<Guid> Task { get; private set; }
public void Run()
{
Task = Task<Guid>.Run(() => entityAccess.CreateEntity<T>(Entity, EntityMethod));
}
}
public class ReadEntityTask<T> : IEntityTask<T>
{
public Guid EntityId { get; private set; }
public Func<Guid, T> EntityMethod { get; private set; }
public Task<T> Task { get; private set; }
public void Run()
{
Task = Task<T>.Run(() => entityAccess.ReadEntity<T>(EntityId, EntityMethod));
}
}
//Furthermore there is a class called EntityTaskManager, which holds a list of these things and runs, awaits & collects the results on them.
public class EntityTaskManager
{
public List<IEntityTask> EntityTasks { get; set; } // I want tasks of Guid and bool in here!!!!
public Dictionary<string, object> EntityTaskResults { get; set; }
}
In a calling class I construct a new EntityTask and add it to the list. And then call RunTasks on the manager.
I'd modify IEntityTask like this:
public interface IEntityTask
{
string Name { get; }
void Run();
object Result { get; }
}
If EntityTaskManager is the only place, where you work with IEntityTask type, the implementation of Result would be explicit:
public class CreateEntityTask<T> : IEntityTask<Guid>
{
/* The rest of code here */
object IEntityTask.Result
{
get { return Task.Result; }
}
}
Then fetching task results should be trivial:
var results = entityTasksManager
.EntityTasks
.Select(t => t.Result);
I need some help transitioning from ValueInjecter to EmitMapper (I've decided so for performance reasons). My use case is one of the most common ones: mapping a Model object to a DTO, based on some rules.
One of this rules is: if a property's type is a subclass of DomainObject, then it should be mapped it to its correspondent DTO. With concrete types that's ok, but I also want it to work with abstract types. The problem is that I don't how to tell EmitMapper which DTO should be used, in a dynamic fashion.
In ValueInjecter code:
public bool IsDomainObjectAndTargetIsDto(ConventionInfo it)
{
return it.SourceProp.Value.IsNotNull()
&& typeof(DomainObject).IsAssignableFrom(it.SourceProp.Type)
&& it.TargetProp.Type.Name.EndsWith("DTO");
}
As all of my DTOs implements DTO<> interface, I thought I could use EmitMapper's DefaultMapConfig.ConvertGeneric method but I just can't figure out how.
Just for completeness, I include my current (not working) code:
public class ModelToDtoConventions()
{
public IMappingConfigurator GetConfig()
{
return new DefaultMapConfig()
.ConvertUsing<IdentificableObject, int>(o => o.Id)
.ConvertGeneric(
typeof (DomainObject),
typeof (DTO<>),
new DefaultCustomConverterProvider(
typeof (DomainObjectToDtoConverter<>)
)
);
}
}
public class DomainObjectToDtoConverter<TDomainObject>
{
public DTO<TDomainObject> Convert(TDomainObject from, object state)
{
return (DTO<TDomainObject>)this.CreateDtoFor(#from);
}
private object CreateDtoFor(object modelObject)
{
var modelType = modelObject.GetType();
var dtoInterface = typeof(DTO<>).MakeGenericType(modelType);
var dtoType = dtoInterface
.GetConcreteSubtypes()
.Single();
return Activator.CreateInstance(dtoType);
}
}
When I try to use this mapping on a test, I'm getting the following exception
'MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model' failed: System.ArgumentException : Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
at EmitMapper.MappingConfiguration.MapConfigBaseImpl.GetGenericConverter(Type from, Type to)
at EmitMapper.MappingConfiguration.MapConfigBaseImpl.FilterOperations(Type from, Type to, IEnumerable`1 operations)
at EmitMapper.MappingConfiguration.DefaultMapConfig.GetMappingOperations(Type from, Type to)
at EmitMapper.EmitBuilders.MappingBuilder.BuildCopyImplMethod()
at EmitMapper.ObjectMapperManager.BuildObjectsMapper(String MapperTypeName, Type from, Type to, IMappingConfigurator mappingConfigurator)
at EmitMapper.ObjectMapperManager.GetMapperInt(Type from, Type to, IMappingConfigurator mappingConfigurator)
at EmitMapper.ObjectMapperManager.GetMapperImpl(Type from, Type to, IMappingConfigurator mappingConfigurator)
at MyProject.WebApi.Adapters.DTOInjector.Transform[TDestination](IMappingConfigurator config, Object source, TDestination destination) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 56
at MyProject.WebApi.Adapters.DTOInjector.CreateDto[TDTO](Object entity) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 47
at MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model() in c:\Users\faloi\Documents\GitHub\api\WebApi.Test\Utils\DTOInjectorTest.cs:line 334 c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs 56
EDIT: this is an example of objects that I'd like to map.
//Domain objects
public class Game
{
public IEnumerable<Map> Maps { get; set; }
public Map MostPlayedMap { get; set; }
public Game()
{
this.Maps = new List<Map>();
}
}
public abstract class Map : DomainObject
{
public string Name { get; set; }
}
public class BombDefuseMap : Map
{
public Player BombHolder { get; set; }
}
public class HostageRescueMap : Map
{
public int QuantityOfHostages { get; set; }
}
//DTOs
public class GameDTO : DTOWithId<Game>
{
public List<MapDTO> Maps { get; set; }
public MapDTO MostPlayedMap { get; set; }
}
public abstract class MapDTO
{
public string Name { get; set; }
}
public class BombDefuseMapDTO : MapDTO, DTO<BombDefuseMap>
{
public int BombHolder { get; set; }
}
public class HostageRescueMapDTO : MapDTO, DTO<HostageRescueMap>
{
public int QuantityOfHostages { get; set; }
}
if you're concerned about performance have a look at this page:
http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection
it's an injections that performs much better but you don't get the value in the matching algorithm,
most times you don't need it anyway
I have a base class like this:
public class BaseResponse
{
public string ErrorMessage { set;get;}
}
And some child classes which inherit from this:
public class Person:BaseResponse
{
public string FirstNAme { set;get;}
}
public class Phone:BaseResponse
{
public string SerialNumber { set;get;}
}
public class Car :BaseResponse
{
public string Year{ set;get;}
}
Now I want to set the ErrorMessage property of each instance of this class to a different value. Currently this is what I am doing:
public Phone GetPhoneError(Phone objPhone)
{
objPhone.ErrorMessage="Err msg related to Phone";
return objPhone;
}
public Person GetPersonError(Person objPerson )
{
objPerson .ErrorMessage="Err msg related to Person";
return objPerson ;
}
... another similar method for Car also
Is there any way I can make this method a generic format so that I don't need 3 separate methods for setting the error message?
public T GetError<T>(T obj) where T: BaseResponse
{
obj.ErrorMessage= string.Format("Err msg related to {0}", typeof(T).Name);
return obj;
}
I don't know if the error message is this generic thing or something custom. If so, then pass the message as an argument.
Why do you need a method for this? Is it because you have simplified the question?
So in your base class you should create a virtual method called SetError (your GetError but with the correct notation).
public abstract string GetErrorMessage(); //In Base Class so that why each implementation will set the correct error message
Then in your base class - also why do you need to return the same object that you are modifying?
public virtual void SetErrorMessage()
{
this.ErrorMessage = GetErrorMessage();
}
You should be able to have a generic method like so:
public object GetError(BaseResponse response)
{
response.ErrorMessage = "whatever";
return response;
}
Why not make property virtual and no need for set in that case ? :
public class BaseResponse
{
public virtual string ErrorMessage { get;}
}
public class Person:BaseResponse
{
.....
public override string ErrorMessage {get { return "Err msg related to Person";}}
}
public class Phone:BaseResponse
{
......
public override string ErrorMessage {get { return "Err msg related to Phone";}}
}
and so on for others....