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....
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);
Is there a way i can have derived classes override the default value of the base class? In the example below i would need the Hammer.Name to return "Hammer".
public class ItemBase
{
public string Name = "Base";
}
public class Hammer: ItemBase
{
new public string Name = "Hammer";
}
public class Test
{
ItemBase MyThing = new Hammer();
// Prints "Base"
Console.WriteLine(ItemBase.Name);
}
You don't need different fields, you need different initializations of the same field.
class Base {
protected string name = "";
public Base() { name = "X"};
}
class Derived : Base {
public Derived() { name = "Y"}; //same {name } field of a Base class
}
You might consider using virtual properties instead of exposing public fields (which is considered bad practice).
As such, you can (with C# 6.0):
void Main()
{
ItemBase myThing = new Hammer();
// Doesn't print "Base"
Console.WriteLine(myThing.Name);
}
public class ItemBase
{
public virtual string Name { get; } = "Base";
}
public class Hammer : ItemBase
{
public override string Name { get; } = "Hammer";
}
or (if you're using older version of C#)...
public class ItemBase
{
public virtual string Name { get { return "Base"; } }
}
public class Hammer : ItemBase
{
public override string Name { get { return "Hammer"; } }
}
You are not defining a new default value in the derived type, you are declaring a completely new field that hides the field with the same name in the base class.
Because fields can't be virtual, the returned field is the one declared in the type through which you are invoking it.
Solution? Don't redeclare a new field, simply assign a new value to the existing field in the constructor of the derived type:
public class Hammer
{
public Hammer() {
Name = "Hammer"; }
}
Trying to figure out what exactly is needed while skating around the .NET version restrictions has been a headache but I have a solution. According to your comments you can use a constructor.
In that case this is really easy to do with properties (which are the preferred way to handle your situation) instead of public fields:
public class ItemBase
{
public ItemBase()
{
//When instantiating ItemBase the value of Name is "Base"
Name = "Base";
}
public string Name { get; set; }
}
public class Hammer : ItemBase
{
public Hammer()
{
//When instantiating Hammer the value of Name is "Hammer"
Name = "Hammer";
}
}
And to test just run this:
public class Program
{
public static void Main()
{
ItemBase itemBase = new Hammer();
Console.WriteLine(itemBase.Name);
itemBase.Name = "Foo";
Console.WriteLine(itemBase.Name);
}
}
Outputs:
Hammer
Foo
This should check off all the boxes. You now use properties (making your code better), each class has a default value, and the properties can be changed after instantiation.
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 attempting to use the command pattern for the first time, and with it create a command factory, I'm following guidance from a pluralsight.com course where he implements an interface for the factory which includes a MakeCommand method.
Now my issue comes from the fact that he simply passes an array of string as the arguments for this method (his is a command line app), however my commands will use a variety of arguments of a variety of types, my plan was to use these commands to store updates to models, so if the application cannot connect to the services, the commands will be queued for when the connection comes back.
This has always been a little bit of a sticking point for me with generic interfaces, how do i handle the multitude of possible arguments?
My first thought was to pass the model itself, with a simple string argument with the command type (Delete, Update, etc) however since my models do not have any common base class or interface i'm left with a similar problem.
Am i missing something basic here?
EDIT : Example of my problem was requested.
I have a CommandFactory Interface as such
public interface ICommandFactory
{
string CommandName { get; }
string Description { get; }
ICommand MakeCommand( ..arguments.. )
}
And i have simple models such as (pure example)
public class Model1
{
public string Name {get;set;}
public int Age {get;set;}
}
public class Model2
{
public DateTime Time {get;set;}
public double Price {get;set}
}
If i wanted to create a command that for example updated a model1, i'm left wondering how the Interface's MakeCommand should look, i can't do MakeCommand(string cmdType, Model1 model) because i have multiple different models which share no common baseclass/interface
It looks like you want the individual models to define how they can be updated. In that case, can you not pass a Function/Action from the Model to the MakeCommand?
public class Model
{
public string Name {get;set;}
public int Age {get;set;}
public void UpdateModel() {...}
}
public interface ICommandFactory
{
string CommandName { get; }
string Description { get; }
ICommand MakeCommand(Action<Model>);
ICommand MakeCommandFunc(Func<Model, bool>);
}
public class Command : ICommand
{
Action<Model> _action;
Command(Action<Model> action)
{
_action = action;
}
Execute()
{
_action();
}
}
EDIT:
As requested, use common interface class to model all classes
public interface IModel
{
void UpdateModel();
}
public class Model1 : IModel
{
public string Name {get;set;}
public int Age {get;set;}
// implement updating of the model
public void UpdateModel() {...do model update...}
}
public class Model2 : IModel
{
public DateTime Time {get;set;}
public double Price {get;set}
// 'dummy' implement updating of the model if this model does not supports updating
public void UpdateModel() { // do nothing or throw NotImplementedException(); }
}
public interface ICommandFactory
{
string CommandName { get; }
string Description { get; }
ICommand MakeCommand( IModel model );
}
I suggest you to use command pattern, this pattern use receiver as object which contains arguments, in your receiver you can add list or dictionary of objects.
In this site you can find source code
link : http://www.dofactory.com/net/command-design-pattern
You could also make the ICommandFactory interface generic like so:
public interface ICommandGeneric
{
void execute();
}
public class CommandOnModel1 : ICommandGeneric
{
private Model1 model;
public CommandOnModel1(Model1 model)
{
this.model = model;
}
public void execute()
{
System.Diagnostics.Debug.WriteLine(model.ToString());
}
}
public interface ICommandFactory <in ModelType>
{
string CommandName { get; }
string Description { get; }
ICommandGeneric MakeCommand(ModelType model, string parameter1);
}
public class Model1
{
}
public class Model1CommandFactory : ICommandFactory<Model1>
{
public string CommandName
{
get { return "CommandOnModel1"; }
}
public string Description
{
get { return "I do stuff on Model1"; }
}
public ICommandGeneric MakeCommand(Model1 model, string parameter1)
{
return new CommandOnModel1(model);
}
}
Having said that, I am not entirely sure you should use a factory and maybe not even the command pattern here.
I'm trying to implement the ITableEntity interface so that I can add [DataContract] attribute on it. But if I implement this interface myself, I'll have to give the ReadEntity and WriteEntity methods a body.
But there is a class that already implements the ITableEntity interface and gave ReadEntity and WriteEntity methods a body, which is the TableEntity.cs.
How can I make my implementation of the interface use the methods in the TableEntity class?
[Edit]
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private TableEntity tableEntity;
public string ETag { get; set; }
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset Timestamp { get; set; }
public SerializableTableEntity()
{
tableEntity = new TableEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}
The reason that every property in your stored table is blank is because WriteEntity and ReadEntity use the blank object to store and write the data.
You're delegating serialization of your object to 'tableEntity' but none of your properties are there.
Suggestion: you will need to implement all of your SerializableTableEntity's properties inside a class that derives from TableEntity, contain a variable of that type inside the SerializableTableEntity entity, and delegate every member's property get/set from SerializableTableEntity to this new object.
Does this make sense?
EDIT: Code sample as requested (you're not going to enjoy it though)
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private CustomEntity tableEntity;
public string ETag {
{
get
{
return tableEntity.ETag;
}
set
{
tableEntity.Etag = value;
}
}
public string PartitionKey
{
get
{
return tableEntity.PartitionKey;
}
set
{
tableEntity.PartitionKey = value;
}
}
public string RowKey
{
get
{
return tableEntity.RowKey;
}
set
{
tableEntity.RowKey = value;
}
}
public DateTimeOffset Timestamp
{
get
{
return tableEntity.Timestamp;
}
set
{
tableEntity.Timestamp = value;
}
}
public string PropertyOne
{
get
{
return tableEntity.PropertyOne;
}
set
{
tableEntity.PropertyOne = value;
}
}
public SerializableTableEntity()
{
tableEntity = new CustomEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}
public class CustomEntity : TableEntity
{
public string PropertyOne { get; set; }
}
I ended up creating exact copy of these classes and made them Serializable. But being able to do some complex queries seems to be a challenge as well. So we moved to SQL Database.
Either delegate the "uninteresting" methods (a more realistic example is here):
class YourClass : Interface {
public void ReadEntity()
{
delegateTo.ReadEntity();
}
TableEntity delegateTo = new TableEntity();
}
or just throw an exception inside them (like NotImplementedException) - the latter will only work for you if those methods are not called.
You can create a class that contains the implementation of the TableEntity class, but also adds the functionality that you want. This is similar to the Decorator Pattern.
[Attributes...]
public class MyTableEntity : ITableEntity {
private TableEntity decoratedTableEntity;
public void ReadEntity(args...) {
decoratedTableEntity.ReadEntity(args...);
}
}
To make the solution more generic, change decoratedTableEntity to be an ITableEntity.