Retrieve property from class through baseclass C# WPF - c#

I have a class called ModelBase:
public abstract class ModelBase : ViewModelBase
{
public ModelBase
{
ProcessObjects.Instance.AddProcessObject(name, this);
}
public abstract void Dispose();
public String Name { get; set; }
....
....
}
public class SomeModel1: ModelBase
{
public String customprop1 { get; set; }
}
public class SomeModel2: ModelBase
{
public String customprop2 { get; set; }
}
I keep a list of all object instances in an application singleton. Now somewhere else in the application I want to retrieve customprop2 from SomeModel2 using this singleton list. I can retrieve the object as modelbase object and cast it:
SomeMethod()
{
if(_obj.Name == "SomeModel2"){
var _obj = obj as SomeModel2;
var _customProp2 = obj.customprop2 ;
}
}
But ideally i want to just try to retrieve the value straight from the object instance by knowing it is there in the parent of the basemodel.
try{
//Some code to automatically cast the object as parent.
var _customProp2 = _obj.customProp2;
}catch{
//Notify user that his request failed
}
The reason for this is that the user can write into a textbox and start a logging function for that particular property.

Can you create a virtual property/method in the base class and override it in your derived class. This way you can retrieve the values from the object with base class reference, whenever you want.

Related

Default value of fields in derived classes

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.

Returning a generic object without knowing the type?

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;
}

c# inheriting from generic class

Let me describe the logic and then class structure. There are objects and all object must inherit from ConfigurationObjectBase. Each object must be owned by Manager and all Managers must be derived from ConfigurationObjectManagerBase. When a new instance of object created, one of the constructor must accept instance of Manager and that instance of Manager must add that instance of object into it's property called ChildObjects. Below is sample of classes. could you pls help to correct in below code acording above business rule? Thanks.
public class ConfigurationObjectBase<ObjectType>
{
public ConfigurationObjectBase(ConfigurationObjectManagerBase<ObjectType> ownerManager)
{
ownerManager.ChildObjects.Add(this);
}
}
public class ConfigurationObjectManagerBase<ObjectType>
{
public ConfigurationObjectManagerBase()
{
ChildObjects = new List<ObjectType>();
}
public List<ObjectType> ChildObjects { get; set; }
}
public class Catalog : ConfigurationObjectBase<Catalog>
{
public Catalog(CatalogManager ownerManager) : base(???)
{
}
}
public class CatalogManager : ConfigurationObjectManagerBase<CatalogManager>
{
public CatalogManager() : base()
{
}
}
There are two issues in your code:
CatalogManager should inherit from ConfigurationObjectManagerBase<Catalog>, not ConfigurationObjectManagerBase<CatalogManager>
ChildObjects should probably be a list of ConfigurationObjectBase<ObjectType>, rather than a list of ObjectType (otherwise you can't add a ConfigurationObjectBase<ObjectType> to it)
So the code should probably look like this:
public class ConfigurationObjectBase<ObjectType>
{
public ConfigurationObjectBase(ConfigurationObjectManagerBase<ObjectType> ownerManager)
{
ownerManager.ChildObjects.Add(this);
}
}
public class ConfigurationObjectManagerBase<ObjectType>
{
public ConfigurationObjectManagerBase()
{
ChildObjects = new List<ConfigurationObjectBase<ObjectType>>();
}
public List<ConfigurationObjectBase<ObjectType>> ChildObjects { get; set; }
}
public class Catalog : ConfigurationObjectBase<Catalog>
{
public Catalog(CatalogManager ownerManager) : base(ownerManager)
{
}
}
public class CatalogManager : ConfigurationObjectManagerBase<Catalog>
{
public CatalogManager()
{
}
}
Also, you don't need to call the default base class constructor (base()), it's done implicitly by the compiler.

How to inherit from class that could be inherited by other classes and keep other classes properties (for view model)

I'm stuck in my inheritances bloating here:
First let me explain the premise of my problem.
My Model:
public class Person
{
[Key]
public int PersonId { get; set; }
[MaxLength(100)]
public string Name { get; set; }
}
public class SuperHero:Person
{
[MaxLength(100)]
public string SuperHeroName { get; set; }
public virtual ICollection<SuperPower> SuperPowers{ get; set; }
}
Now, I am trying to create my viewModels for my MVC website, I have those base classes that need to be inherited by all other viewmodel displaying/editing a Person/SuperHero:
public class BasePersonViewModel
{
public string Name { get; set; }
ctors()
}
public class BaseSuperHeroViewModel : BasePersonViewModel
{
public List<string> SuperPowers{ get; set; }
ctors()
}
Here is where I am stuck, I am trying to define only one ViewModel that could be used regarless of the base class and access property of Person and/or SuperHero (if the Person is a superhero). I've been pulling my hair out but so far only found a solution which i don't like:
Example:
public class SomeViewModel<T> where T : BasePersonViewModel
{
public BasePersonViewModel obj;
public DateTime BirthDate { get; set; }
public SomeViewModel(Person data) //: base(data)
{
if (data is SuperHero)
obj = new BaseSuperHeroViewModel (data);
else
obj = new BasePersonViewModel(data);
}
}
While this would work it's really not sexy to use. And on top of that, I could have another ViewModel that inherit from SomeViewModel as well.
Is there a cleaner way to achieve this?
Edit
My main goal is to be able to able to cast my SomeViewModel depending on the one of the baseclass. Let's say do something like in my Controller:
if myclass is SomeViewModel (of type SuperHero)
Exactly how you do it for Person/SuperHero db retrival/check
var data = context.Person.first(w=> w.Id==1)
if (data is SuperHero)
..
I would like this because I would like to use the same viewmodel let's say to list superhero and person, and just display slightly differently if it's a superhero
Edit 2
I was trying to avoid using the whole Model.Obj to be able to see it directly with the Model... But the more i think about it, the more I think this is not possible really... On top of that I would like to extend some other superHero specific properties in SomeViewModel (only if SomeViewModel is a superhero), that are not declared in the BaseSuperHeroModel one... Let's say in SomeViewModel I want the field 'ComesFromPlanet' only if superhero.
Edit 3
I thought about another way to do it, but it obviously creating various ViewModel.
For the most general case (all fields that are shared for all Person) I would keep my base:
public class BasePersonViewModel
{
public string Name { get; set; }
ctors()
}
I interface specific Person:
public Interface IBaseSuperHero
{
[MaxLength(100)]
public string SuperHeroName { get; set; }
public List<string> SuperPowers{ get; set; }
}
I would keep as well OtherViewModel like this:
public class SomeViewModel:BasePersonViewModel
{
Public datetime Birthdate {get;set;}
}
Then I would create a specific SomeviewModel for other Person inheritant and used interfaces to have old and new properties.
For example:
public class SomeViewModelSuperHero:SomeViewModel, IBaseSuperHero
{
public string OriginalPlanet {get;set;}
}
Is this a clean solution?
Sorry I'm sure I am not clear about this, but I try !
Thanks for your input and time.
I am trying to define only one ViewModel that could be used regarless of the base class and access property of Person and/or SuperHero (if the Person is a superhero)
Assuming you'd return default values for super-hero properties when the model is not a super-hero, you could do something like this:
public class PersonOrSuperHeroViewModel {
private Person person;
private SuperHero superHero;
public PersonOrSuperHeroViewModel(Person personOrSuperHero) {
if (personOrSuperHero is SuperHero) superHero = personOrSuperHero;
person = personOrSuperHero;
}
public IsSuperHero { get { return superHero != null; } }
... // super-hero properties only work when IsSuperHero == true
}
How about something like
public class Person {
public virtual BasePersonViewModel MainViewModel {
get { return new BasePersonViewModel(this);}
}
}
public class SuperHero : Person {
public override BasePersonViewModel MainViewModel {
get { return new BaseSuperHeroViewModel(this);}
}
}
So if all your people classes override the MainViewModel property to return the appropriate view, you don't need
public BasePersonViewModel obj;
public SomeViewModel(Person data) {
if (data is SuperHero)
obj = new BaseSuperHeroViewModel (data);
else
obj = new BasePersonViewModel(data);
}
Because you can have
public BasePersonViewModel obj;
public SomeViewModel(Person data) { obj = data.MainViewModel; }
which will work however many subclasses of person you have.

Design problem: Get child object type information avoiding if statements in presentation layer

I have a customer hierarchy like so:
abstract class Customer {
public virtual string Name { get; set; }
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
When I retrieve a Customer, I would like to show on the web form the properties to edit/modify. Currently, I use if statements to find the child customer type and show the specialized properties. Is there a design pattern (visitor?) or better way so I can avoid the "if" statements in presentation layer? How do you do it?
Further information: This is an asp.net website with nHibernate backend. Each customer type has its own user control on the page that I would like to load automatically given the customer type.
Can you use reflection to get the list of properties specific to an subclass (instance)? (Less error-prone.)
If not, create a (virtual) method which returns the special properties. (More error prone!)
For an example of the latter:
abstract class Customer {
public virtual string Name { get; set; }
public virtual IDictionary<string, object> GetProperties()
{
var ret = new Dictionary<string, object>();
ret["Name"] = Name;
return ret;
}
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Max spending"] = MaxSpending;
return ret;
}
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Award"] = Award;
return ret;
}
}
You probably want to create sections (fieldsets?) on your Web page, anyway, so if would come into play there, making this extra coding kinda annoying and useless.
I think a cleaner organization would be to have a parallel hierarchy of display controls or formats. Maybe use something like the Abstract Factory Pattern to create both the instance of Customer and of CustomerForm at the same time. Display the returned CustomerForm instance, which would know about the extra properties and how to display and edit them.
new:
interface CustomerEdit
{
void Display();
}
edit:
abstract class Customer {
protected CustomerEdit customerEdit; // customers have an object which allows for edit
public virtual string Name { get; set; }
public void Display() { customerEdit.Display(); } // allow the CustomerEdit implementor to display the UI elements
}
// Set customerEdit in constructor, tie with "this"
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
// Set customerEdit in constructor, tie with "this"
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
usage:
Customer whichCouldItBe = GetSomeCustomer();
whichCouldItBe.Display(); // shows UI depeneding on the concrete type
Have you tried something like this:
public class Customer<T>
where T : Customer<T>
{
private T subClass;
public IDictionary<string, object> GetProperties()
{
return subClass.GetProperties();
}
}
With a subclass of:
public class FinancialCustomer : Customer<FinancialCustomer>
{
}
This is off the top of my head so might not work. I've seen this type of code in CSLA.NET.
Here's the link to the CSLA.NET class called BusinessBase.cs which has a similar definition to what I've given above.

Categories