Let's say I've got a class:
public class Parent
{
public string Name { get; set; }
public string City { get; set; }
}
and in some function I'm getting the list of objects type Parent, next I'd like to extend those objects with new field with some value, so I'm declaring an extended class like this:
public class Child : Parent
{
public Child(Parent parent)
{
Name = parent.Name;
City = parent.City;
}
public int Age { get; set; }
}
and call the costructor for each extended object. Is there a better way to do that? What if there will be multiple properties in Parent? Maybe there is some more elegant way to achieve that?
I think maybe you're looking for a copy-constructor pattern. Each level defines a protected constructor which copies the relevant properties:
public class Parent
{
public string Name { get; set; }
public string City { get; set; }
//normal constructor
public Parent()
{
}
protected Parent(Parent copy)
{
this.Name = copy.Name;
this.City = copy.City;
}
}
The Child would inherit from Parent, pass it down through to the copy-constructor, then append its new values as desired:
public class Child : Parent
{
public string NewInfo { get; set; }
public Child(Parent copy)
: base(copy)
{
}
}
Usage might look like:
Parent parent = new Parent() { Name = "Name", City = "StackOverflow"};
Child child = new Child(parent) { NewInfo = "Something new!" };
Console.WriteLine(child.Name); //Name
Console.WriteLine(child.City); //StackOverflow
Console.WriteLine(child.NewInfo); //Something new!
The benefit from this is that you can have multiple levels of inheritance with each level managing their own properties.
EDIT: Given your most recent comment:
The motivation to this question is a situation in where I'm getting a
list of objects with data, and want to show this data but with some
additional fields, without touching the base class.
Perhaps the better method then is to wrap the base class:
public class Child
{
private readonly Parent WrappedParent;
public string NewInfo { get; set; }
public string Name
{
get { return WrappedParent.Name; }
set { WrappedParent.Name = value; }
}
public string City
{
get { return WrappedParent.City; }
set { WrappedParent.City = value; }
}
public Child(Parent wrappedParent)
{
this.WrappedParent = wrappedParent;
}
}
Downside is you have to redeclare each property, and you are no longer inheriting (cannot be considered a) "Parent", but then you are definitly "not touching" the base class anymore. Could move the "Parent" properties into an IParent interface if that's better for you, but doing so again is "touching" the base class as you'll have to add the IParent interface declaration to its class definition.
Not sure if I got you wrong, but this could be a more standar solution
public class Parent
{
public Parent(string name, string city)
{
Name = name;
City = city;
}
public string Name { get; set; }
public string City { get; set; }
}
public class Child : Parent
{
public Child(string name, string city, int age) : base(name, city)
{
Age = age;
}
public int Age { get; set; }
}
You can do this
public class Parent
{
public string Name { get; set; }
public string City { get; set; }
public Parent(string name, string city)
{
this.Name = name;
this.City = city;
}
public Parent():this(string.Empty, string.Empty)
{
}
}
public class Child : Parent
{
public Child(Parent parent, int age):base(parent.Name, parent.City)
{
this.Age = age;
}
public int Age { get; set; }
}
Related
public sealed class ParentSource
{
public string Name { get; }
public List<ChildSource> Children { get; }
public ParentSource(string name)
{
Name = name;
Children = new List<ChildSource>();
}
}
public sealed class ChildSource
{
public string Name { get; }
public ChildSource(string name)
{
Name = name;
}
}
public sealed class ParentDestination
{
public string Name { get; }
public List<ChildDestination> Children { get; }
public ParentDestination(string name)
{
Name = name;
Children = new List<ChildDestination>();
}
}
public sealed class ChildDestination
{
public string Name { get; }
public ChildDestination(string name)
{
Name = name;
}
}
To my understanding, all I need are the following mappings:
CreateMap<ParentSource, ParentDestination>();
CreateMap<ChildSource, ChildDestination>();
Call the mapping:
var parentSource = new ParentSource("parent");
var childSource = new ChildSource("child");
parentSource.Children.Add(childSource);
var parentDestination = mapper.Map<ParentSource, ParentDestination>(parentSource);
The child collection of the destination parent doesn't contain any members unless I add a public setter to the Children property. How can I make this work without a public setter?
I have a Json class "GetAllDevices()". My JSON response consists of an Array/List of objects, where each object has the below common properties.
public class GetAllDevices
{
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("actions")]
public Action[] Actions { get; set; }
public class Action
{
public string _id { get; set; }
public Action_Def action_def { get; set; }
}
public class Action_Def
{
public string _id { get; set; }
public string name { get; set; }
}
}
I want to create 2 generic lists containing all the above properties based on its "type".
lstfoo1 List contains all the properties(_id, name type and actions) where type="foo1". Similarly, lstfoo2 is a List which contains the above properties where type="foo2".
What I have done so far:
string strJson=getJSON();
Foo1 lstfoo1=new Foo1();
Foo2 lstfoo2=new Foo2();
List<Foo1> foo1list= lstfoo1.GetDeviceData(strJson);
List<Foo2> foo2list = lstfoo2.GetDeviceData(strJson);
public class AllFoo1: GetAllDevices
{
}
public class AllFoo2: GetAllDevices
{
}
public abstract class HomeDevices<T>
{
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1{ get; set; }
public List<AllFoo2> lstfoo2{ get; set; }
public abstract List<T> GetDeviceData(string jsonResult);
}
public class Foo1: HomeDevices<AllFoo1>
{
public Foo1()
{
type = "foo1";
}
public override List<AllFoo1> GetDeviceData(string jsonResult)
{
var lst =Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo1>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
public class Foo2: HomeDevices<AllFoo2>
{
public Foo2()
{
type = "foo2";
}
public override List<AllFoo2> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AllFoo2>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
My question is, is there an easier way to do this using abstract classes? Can I directly convert my "GetAllDevices" class into an abstract class and inherit it and deserialize into it and create a generic list?
This should help, if I understand your problem correctly. Let me know if you have questions or it doesn't work as you need. I put this together really quickly without testing.
The way the Type property is defined could be improved but I left it as you had it.
public class MyApplication
{
public void DoWork()
{
string json = getJSON();
DeviceTypeOne foo1 = new DeviceTypeOne();
DeviceTypeTwo foo2 = new DeviceTypeTwo();
IList<DeviceTypeOne> foo1Results = foo1.GetDeviceData(json); // calls GetDeviceData extension method
IList<DeviceTypeTwo> foo2Results = foo2.GetDeviceData(json); // calls GetDeviceData extension method
}
}
// implemented GetDeviceData as extension method of DeviceBase, instead of the abstract method within DeviceBase,
// it's slightly cleaner than the abstract method
public static class DeviceExtensions
{
public static IList<T> GetDeviceData<T>(this T device, string jsonResult) where T : DeviceBase
{
IEnumerable<T> deviceDataList = JsonConvert.DeserializeObject<IEnumerable<T>>(jsonResult);
IEnumerable<T> resultList = deviceDataList.Where(x => x.Type.Equals(typeof(T).Name));
return resultList.ToList();
}
}
// abstract base class only used to house common properties and control Type assignment
public abstract class DeviceBase : IDeviceData
{
protected DeviceBase(string type)
{
if(string.IsNullOrEmpty(type)) { throw new ArgumentNullException(nameof(type));}
Type = type; // type's value can only be set by classes that inherit and must be set at construction time
}
[JsonProperty("_id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; private set;}
[JsonProperty("actions")]
public DeviceAction[] Actions { get; set; }
}
public class DeviceTypeOne : DeviceBase
{
public DeviceTypeOne() : base(nameof(DeviceTypeOne))
{
}
}
public class DeviceTypeTwo : DeviceBase
{
public DeviceTypeTwo() : base(nameof(DeviceTypeTwo))
{
}
}
// implemented GetAllDevices class as IDeviceData interface
public interface IDeviceData
{
string Id { get; set; }
string Name { get; set; }
string Type { get; }
DeviceAction[] Actions { get; set; }
}
// renamed and relocated class Action to DeviceAction
public class DeviceAction
{
public string Id { get; set; }
public DeviceActionDefinition DeviceActionDefinition { get; set; }
}
// renamed and relocated Action_Def to DeviceActionDefinition
public class DeviceActionDefinition
{
public string Id { get; set; }
public string Name { get; set; }
}
It should be simple enough to move the implementation of method GetDeviceData() to the base class.
For this to work, you will need to add a constraint on T so the compiler knows a bit more about the base type. You will also need to implement a constructor to populate the concrete type's type string you use around. This is a necessary measure to ensure the value is always populated as it is used for comparison in the method in question:
public abstract class HomeDevices<T> where T: GetAllDevices
{
public HomeDevices(string concreteType)
{
type = concreteType;
}
public string type { get; set; }
public string _id { get; set; }
public List<AllFoo1> lstfoo1 { get; set; }
public List<AllFoo2> lstfoo2 { get; set; }
//This method is now generic and works for both.
public List<T> GetDeviceData(string jsonResult)
{
var lst = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(jsonResult);
var lst1 = lst.Where(x => x.Type.Equals(type)).ToList();
return lst1;
}
}
I hope that helps.
I am using a client to call an API. In the API - I want the model to populate from the request body - but I want the model to be structured differently depending upon the name of a single property. Basically I want to create something like a switch/case scenario with a data model, but am unsure how to implement this. The last model contains pseudo code based upon what I want to acheive (obviously generic type won't work in the way I described, but I feel it completes my example). Here's my example:
Controller:
[HttpPost("customer", Name = "Submit Customer")]
public IActionResult ActivateCustomer([FromBody]Customer customer)
{
//Do something with the Customer object.
return Ok();
}
Customer Model:
public class Customer
{
public CustomerInfo customerInfo { get; set; }
public SponserInfo sponserInfo { get; set; }
}
CustomerInfo:
public class CustomerInfo
{
public int CustomerId { get; set; }
public string CustomerName { get; set; }
//etc.
}
SponserA:
public class SponserA
{
public int ReferenceId { get; set; }
public string Password { get; set; }
}
SponserB:
public class SponserB
{
public string UserName{ get; set; }
public string Relation { get; set; }
public string Department { get; set; }
}
SponserInfo: (pseudo-code of what I would like)
public class SponserInfo
{
public string SponserName { get; set; }
public T SponserInfo { get; set; }
switch(this.SponserName)
{
case "Sponser A's Name":
T = SponserA;
break;
case "Sponser B's Name":
T = SponserB;
break;
}
}
How about something like this:
public abstract class SponsorInfo
{
public string SponserName { get; set; }
protected SponsorInfo(string sponserName)
{
SponserName = sponserName;
}
}
public class SponsorA : SponsorInfo
{
public int ReferenceId { get; set; }
public string Password { get; set; }
public SponsorA(string sponserName, int referenceId, string password)
: base(sponserName)
{
ReferenceId = referenceId;
Password = password;
}
}
public class SponsorB : SponsorInfo
{
public string UserName { get; set; }
public string Relation { get; set; }
public string Department { get; set; }
public SponsorB(string sponsorName, string userName, string relation, string department)
: base(sponsorName)
{
UserName = userName;
Relation = relation;
Department = department;
}
}
Then, leave your Customer class alone (but fix the typo):
public class Customer
{
public CustomerInfo customerInfo { get; set; }
public SponsorInfo sponsorInfo { get; set; }
}
and in your controller, add the switch statement and construct either a SponsorA or a SponsorB depending on what the data looks like. Either of those is a SponsorInfo, so you can attach it as the sponsorInfo in your Customer object.
Here's one extensible way.
An attribute maps the sponsor name to the subclass, so SponsorInfo doesn't have to be aware of all subclasses.
It uses an abstract base class (Sponsor) for all Sponsor types (as also recommended by #Flydog57).
When SponsorInfo.SponsorName is assigned, the instance of a subclass of this is created (so you have to assign SponsorName first).
You can adjust that depending on how you actually map the properties from your model.
using System;
using System.Linq;
using System.Reflection;
/// <summary>
/// Attribute to indicate the name mapped to a <see cref="Sponsor"/> subclass.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class SponsorAttribute : Attribute
{
public SponsorAttribute(string name)
{
this.Name = name;
}
/// <summary>
/// The value that <see cref="SponserInfo.SponserName"/> must match for the attribute class to be used.
/// </summary>
public virtual string Name { get; set; }
}
public abstract class Sponsor
{
public int ReferenceId { get; set; }
public string Password { get; set; }
}
[Sponsor("Sponser A's Name")]
public class SponsorA : Sponsor
{
}
[Sponsor("Sponser B's Name")]
public class SponsorB : Sponsor
{
public string Department { get; set; }
}
// More subclasses can be added.
public class SponsorInfo
{
/// <summary>
/// The Sponsor name.
/// Changing this sets <see cref="Sponsor"/> to a new instance of the corresponding class.
/// </summary>
public string SponsorName
{
get { return _sponsorName; }
set
{
if (_sponsorName != value)
{
_sponsorName = value;
// Find a Sponsor subclass with a SponsorAttribute.Name matching the given value:
Type sponsorType = Assembly.GetExecutingAssembly().GetTypes() // you might want to also scan other assemblies
.Where(t =>
t.IsSubclassOf(typeof(Sponsor))
&& (t.GetCustomAttribute<SponsorAttribute>()?.Name?.Equals(_sponsorName) ?? false)
).FirstOrDefault(); // null if none is found
if (sponsorType == null)
Sponsor = null; // no matching class
else
Sponsor = (Sponsor)Activator.CreateInstance(sponsorType); // new instance of the matching class
}
}
}
private string _sponsorName;
public Sponsor Sponsor { get; set; } // renamed from "SponsorInfo" because that's the name of this class
}
This is dual licensed as public domain (CC0) and the normal licensing of Stack Overflow.
Why not create a model called Sponsor that has all your fields, and then if ReferenceId is null, you'll know which kind of sponsor it is?
public class SponsorInfo
{
public int? ReferenceId { get; set; }
public string Password { get; set; }
public string UserName { get; set; }
public string Relation { get; set; }
public string Department { get; set; }
}
[HttpPost("customer", Name = "Submit Customer")]
public IActionResult ActivateCustomer([FromBody]Customer customer)
{
//Do something with the Customer object.
if (customer.sponsorInfo.ReferenceId == null || !customer.sponsorInfo.ReferenceId.HasValue)
{
//is SponsorB
}
else
{
//is SponsorA
}
return Ok();
}
I'm having a problem defining these 2 classes:
public class Article
{
public Article(long ID, string Name, ArticleFamily Family)
{
//...Initializer...
}
public ArticleFamily Family { get; set; }
//Other props...
}
public class ArticleFamily
{
public ArticleFamily(int ID, string Description)
{
//...Initializer...
}
public int ID { get; private set; }
public string Description { get; set; }
}
I have a collection of Article and each one belongs to a family.
Now, given that I have a certain ArticleFamily object I should be able to change its Description and it gets eventually persisted to a DataBase. (I left out that part for simplicity)
But I should not be able to do this:
Article art = SomeMethodReturningArticle();
art.Family.Description = "SomeOtherValue";
I should be able to change the Family of an Article entirely, replacing it with a new ArticleFamily object, but I shouldn't be able to change just the description.
Should I create a copy of the ArticleFamily class with readonly properties like this:
public class ArticleFamilyReadonly
{
ArticleFamily _family;
public ArticleFamilyReadonly(ArticleFamily Family)
{
_family = Family;
}
public int ID { get { return _family.ID; } }
//etc...
}
How can I do this in a clean way?
Here's what I threw together in LinqPad:
void Main()
{
var art = new Article(1,"2", new ArticleFamily(1, "Test"));
art.Family.Description = "What?"; // Won't work
var fam = art.Family as ArticleFamily;
fam.Description = "This works"; // This works...
}
public class Article
{
public Article(long ID, string Name, IArticleFamily Family)
{
//...Initializer...
}
public IArticleFamily Family { get; set; }
//Other props...
}
public class ArticleFamily : IArticleFamily
{
public ArticleFamily(int ID, string Description)
{
//...Initializer...
}
public int ID { get; private set; }
public string Description { get; set; }
}
public interface IArticleFamily
{
int ID { get; }
string Description { get;}
}
Cannot edit directly from the Article object unless cast to ArticleFamily object.
I have 3 classes called Student,Worker,People which may come from different project.All of them have the two same property: name,age.Now when I want to change People to Student,I have to write a method called ChangePeopleToStudent, when I want to change People to Worker,I have to write a method called ChangePeopleToWorker.I try to use generic methods to write only one method,but it seems wrong.How to fix it?
Three classed
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public int MathPoint { get; set; }
}
public class Worker
{
public string Name { get; set; }
public int Age { get; set; }
public string WorkPlace { get; set; }
}
public class People
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
}
My two change method
public static Student ChangePeopleToStudent(People people)
{
return new Student
{
Name = people.Name,
Age = people.Age
};
}
public static Worker ChangePeopleToWorker(People people)
{
return new Worker
{
Name = people.Name,
Age = people.Age
};
}
Generic methods:How to fix it?
public static T ChangePeopleToWorker<T>(People people)
where T : Student, Worker,new T()
{
return new T
{
Name = people.Name,
Age = people.Age
};
}
Create an interface (or a base class - I'm assuming an interface in my example) e.g.:
public interface IPerson
{
string Name { get; set; }
int Age { get; set; }
}
It should be implemented by all your classes. Then you'll be able to write:
public static T ChangePersonTo<T>(IPerson person)
where T : IPerson, new T()
{
return new T
{
Name = person.Name,
Age = person.Age
};
}
.NET does not support multiple inheritance, so where T : Student, Worker is not a plausible condition. If you want T to be either Student or Worker you'll need to define a common base class (or interface), or define two different methods.
If People should be the common class between the two you can simplify your classes:
public class Student : People
{
public int MathPoint { get; set; }
}
public class Worker : People
{
public string WorkPlace { get; set; }
}
public class People
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
}