I'm wondering if someone can help me with what is the best way to populate the base properties of a derived class. I would like to use one method to populate the properties of the base whether the base or the child is being used.
Here is an example of what I am asking:
public class Parent
{
public string Id {get; set;}
}
public class Child : Parent
{
public string Name {get; set;}
}
public Parent GetParent(int ID)
{
Parent myParent = new Parent();
//Lookup and populate
return Parent;
}
public Child GetChild(string name)
{
Child myChild = new Child();
//Use the GetParent method to populate base items
//and then
//Lookup and populate Child properties
return myChild;
}
I think you might be overcomplicating things a bit. Take a look at this code that uses inheritance and constructors to initialize objects:
public class Parent
{
public string Id {get; set;}
public Parent(string id)
{
Id = id;
}
}
public class Child : Parent
{
public string Name {get; set;}
public Child(string id, string name) : base(id) // <-- call base constructor
{
Name = name;
}
}
It uses constructors for initialization and the base keyword to call the parent constructor from the derived class. I would go this direction unless you really need to have a factory method construct your object.
Something like this if you don't want to do it in constructor.
Note: the constructor is not always called, especially if the type is desirialized using certain serializators.
public class Parent
{
public string Id {get; set;}
public virtual void InitPorperties() {
//init properties of base
}
}
public class Child : Base {
public override void InitProperties() {
//init Child properties
base.InitProperties();
}
}
After this you can use it like:
public Parent GetParent(int ID)
{
var myParent = new Parent();
parent.InitProperties();
return myParent;
}
public Parent GetChild(int ID)
{
var child= new Child();
child.InitProperties();
return child;
}
As anything it has other side of coin: the caller has to call InitProperties method in oder to get correctly initialized object.
If the serialization/desialization is not a concern in your case, stick with constructors, in practice call this methods inside ctors of every type (Parent, Child)
If you dont want to use a standard way to just
Child myChild = new Child();
myChild.Name = "name";
myChild.Id = "1";
You can populate them via the constructor like this.
public class Parent
{
public Parent(string id)
{
Id = id;
}
public string Id { get; set; }
}
public class Child : Parent
{
public Child(string id, string name)
: base(id)
{
name = Name;
}
public string Name { get; set; }
}
And when you isntanciate it
Child myChild = new Child("1", "name");
Which in my opinion is a quite neat way to do it.
Related
I have a base class with a public property.
public class Parent
{
public string Name {get; set;}
}
I want that field will be calculated in the child constructor
public class Child1 : Parent
{
public Child1(string a, string b)
{
this.Name = a + " " + b;
}
}
And I want to mask or decrease visibility of Name in the child.
That we will not be able to do
var l = new Child1("aa", "bb");
l.Name = "something else";
I am pretty sure that what I am trying to achieve is impossible and against Liskov substitution principle.
Any idea about this?
This sounds less like a parent/child relationship or another case of Polymorphy.
I do not know of a accesor that would say "public in this class, but not inheritors". And not just for C#, but any OOP langauge I learned.
It sounds more like a a case for encapsulation:
public class Child1 {
Parent _backingField; //Set in constructor
public string ParentName {
get { return _backingField.Name; }
//No setter
}
}
One of the first things you learn in MVVM: If polymorphy can not do that or you do not have enough control over the class, just encapsulate it into something you do have full control over.
Edit:
In a more advanced view, with a abstract base class:
public abstract class Person {
public string Name {get; set;}
}
public class Parent : Person {
//I know of no property parent could have, that person does not
//Even the concept of a parent name, sounds more like a "Person" thing
}
public class Child1 : Person {
Parent _backingField; //Set in constructor
public string ParentName {
get { return _backingField.Name; }
//No setter
}
}
Alternatively, just make one class:
public class Person {
//Every person has a parent
Person _backingField; //Set in constructor
public string ParentName {
get { return _backingField.Name; }
//No setter
}
//And of course it's own name
public string Name {get; set;}
}
Why not passing name to Parent constructor like that?
public class Parent
{
public string Name { get; private set; } // private set; can be skipped
public class Parent(string name)
{
Name = name;
}
}
Then Child class would look like this
public class Child : Parent
{
public Child(string a, string b)
: base(a + b)
{ }
}
If you are not able to make change in base class there is alternative solution (partially only)
public class Parent
{
public string Name { get; set; }
}
public class Child : Parent
{
public new string Name
{
get => base.Name;
private set => base.Name = value;
}
public Child(string a, string b)
{
Name = $"{a} {b}";
}
}
But there is quick workaround for encapsulation...
Child c = new Child("abc", "def");
c.Name = "New name"; // this will cause compilation error
Parent p = c; // this is perfectly legal
p.Name = "HACKED!";
Let's assume I have the following interfaces:
public interface IChild
{
IParent MyParent { get; }
string Name { get; set; }
}
public interface IParent : IChild
{
IEnumerable<IChild> Children { get; }
}
In addition for the parent implementation there is the following abstract class:
public abstract class Parent : IParent
{
private List<IChild> _children = new List<IChild>();
public Parent(IParent parent, string name)
{
Name = name;
MyParent = parent;
}
public IEnumerable<IChild> Children => _children;
public IParent MyParent { get; }
public string Name { get; set; }
protected void Add(IChild child)
{
_children.Add(child);
}
protected void Remove(IChild child)
{
_children.Remove(child);
}
}
Now I use the following implementation based on the interfaces and abstract class above:
public class Tree : Parent
{
private Branch _left;
private Branch _right;
private Leaf _goldenLeaf;
public Tree(IParent parent, string name) :
base(parent, name)
{
_left = new Branch(this, "left branch");
Add(_left);
_right = new Branch(this, "left branch");
Add(_right);
_goldenLeaf = new Leaf(this, "the golden leaf");
Add(_goldenLeaf);
}
}
public class Branch : Parent
{
private Leaf _singleLeaf;
public Branch(IParent parent, string name) :
base(parent, name)
{
_singleLeaf = new Leaf(this, "the golden leaf");
Add(_singleLeaf);
}
}
public class Leaf : IChild
{
public Leaf(IParent parent, string name)
{
MyParent = parent;
Name = name;
}
public IParent MyParent { get; }
public string Name { get; set; }
public void DoSomething()
{
// How can I have a method in the parent which can only be called
// by the corresponding child. How to prevent the outside to call
// the method "Inform" on the parent?
MyParent.AskBeforeExecute(this, "data");
}
}
The main problem I have is that I want to call a method from the parent within the "DoSomething" call which is only accessible by the children. So the "AskBeforeExecute" method can not be in the public interface of the IParent definition because then the "outer" world can also call this method. I am not sure if my idea can be implemented at all with interface as I have right now. Anyway I am stuck a little bit and I am looking for a better pattern or idea to handle this?
Say I have:
public class Parent{
[ApiMember(Name = "parentItem")]
public string Item {get; set;}
}
and
public class Child : Parent {
[ApiMember(Name = "childItem")]
public new string Item {get; set;}
}
Since the 'Item' property in the parent class should be hidden, why does making a request with {"childItem": "something"} returns Could not find property childItem on RequestObject? That said, what is the best way (or is there a way) to rename inherited API members/properties in the subclass?
[DataContract] and [DataMember] attributes affect serialization where as [Api*] attributes are only used to document and add extra metadata about your API, but it doesn't affect serialization behavior.
So you should instead change your DTOs to:
[DataContract]
public class Parent
{
[DataMember(Name = "parentItem")]
public virtual string Item { get; set; }
}
[DataContract]
public class Child : Parent
{
[DataMember(Name = "childItem")]
public override string Item { get; set; }
}
Where they will be used when serializing in most of ServiceStack's serializers, e.g:
var json1 = new Parent { Item = "parent" }.ToJson();
json1.Print();
var json2 = new Child { Item = "child" }.ToJson();
json2.Print();
Which outputs:
{"parentItem":"parent"}
{"childItem":"child"}
You can try this example Live on Gistlyn.
Try making the property virtual in the parent and then simply override it (without new keyword) in the child class like that:
public class Parent{
[ApiMember(Name = "parentItem")]
public virtual string Item {get; set;}
}
public class Child : Parent {
[ApiMember(Name = "childItem")]
public override string Item {get; set;}
}
I am using ASP.Net Web API 2 and want to create some complex input parameter classes.
I have classes in my library as
public class GrandParent
{
public int Id {get;set;}
public string GrandParentName {get;set;}
}
public class Parent : GrandParent
{
public string ParentName {get;set;}
}
Now I only need Parent class properties in my child class and I am doing so
public class Child : Parent
{
public string ChildName {get;set;}
}
When I create object of Child class, I want only two properties, which are
Child objChild = new Child();
objChild.ParentName;
objChild.ChildName;
I don't want GrandParentName property with objChild. Is there any way to skip grand parent classes in inheritance structure as I want to pass this class as API action parameter.
I am feeling lack of multiple inheritance in C# here.
I may be misunderstanding something but I think you are going too far with inheritance. You might look to the composite pattern.
I think you are confused between the role of each object compared to each others and inheritance. I am not sure you need all these classes. Here is what I would do :
interface IPerson
{
public int Id { get; set; }
public string Name { get; set; }
public string ParentName { get; }
}
class Person : IPerson
{
public int Id { get; set; }
public string Name { get; set; }
protected IPerson Parent { get; set; }
public string ParentName { get { return this.Parent != null ? this.Parent.Name : String.empty; } }
public Person(IPerson parent = null)
{
this.Parent = parent;
}
}
And once you have this, you can achieved what you want :
var grandParent = new Person();
var parent = new Person(grandParent);
var child = new Person(parent);
I hope I didn't miss any crucial point :D.
As it seems, you may need to change your GrandParent from class to interface, then that might work, if you need those properties just make extra class that implements interface. Remember that you can implement as many interfaces as you need on a single class. And still they have common name for use in Lists and stuff.
fharreau gave example.
If you want better example you should make some data diagram concerning data in question.
I have the following classes:
public class ParentClass
{
public string Name {get;set;}
public int Age {get;set;}
}
public class SubClass : ParentClass
{
public int Id {get;set;}
}
and I have the following method:
public void InsertSubClass(ParentClass parentClass)
{
SubClass subClass = new SubClass();
subClass.Id = 1;
subClass.Age = parentClass.Age;
subClass.Name= parentClass.Name;
}
How can I refactor this method in such a way that I dont need to assign the properties of the parameter ParentClass into properties of SubClass one by one?
Are there any alternative which is more efficient? or this is really how to do it? Im just thinking that if the properties are many, this could be tedious..
Thanks in advance. :)
you can achieve this thing by creating copy constructor. Anyways you would have to assign parent class properties somewhere as casting wont work in this case.
Here is copy constructor way that assigns parent property in parent constructor.
public class ParentClass
{
public string Name { get; set; }
public int Age { get; set; }
public ParentClass()
{
}
//Copy constructor
public ParentClass(ParentClass parentClass)
{
this.Name = parentClass.Name;
this.Age = parentClass.Age;
}
}
public class SubClass : ParentClass
{
public int Id { get; set; }
public SubClass(ParentClass parentClass, int id) : base(parentClass)
{
this.Id = id;
}
}
And now method looks like this.
public static void InsertSubClass(ParentClass parentClass)
{
SubClass subClass = new SubClass(parentClass, 1);
}
Update
If you can not make changes to your parent and child class then how about creating an extension method for the parent class in static class like below.
public static void ShallowConvert<T, U>(this T parent, U child)
{
foreach (PropertyInfo property in parent.GetType().GetProperties())
{
if (property.CanWrite)
{
property.SetValue(child, property.GetValue(parent, null), null);
}
}
}
Note: This might not work with private properties and fields.
You can not assign parent class to child's base object like this child.base = parent. Also you can not cast paret class to child like var o = (child)parent; o.id=1; All you can do is add constructor to child class that receives parent class and do work in that constructor.