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!";
Related
In order to make an export, I need to overload an object in order to add a property which will transform a property from master class :
public class A
{
public int MyProperty1 { get; set; };
public int MyProperty2 { get; set; };
/*...*/
public myType MyPropertyN { get; set; };
}
public class B : A
{
public override string MyProperty1
{
get :
{
return A.MyProperty1.ToString();
}
set :
{
a.MyProperty1 = int.parse(value);
}
}
}
The problem is my A objects are already instantiated because the model come from the database.
I'm looking for a solution where I can do something like this :
var List<A> myListOfA = PopulateFromSomewhere();
var List<B> myListOfB = myListOfA.Select(x => new B(x)).ToList();
Where A will be copied in B and after call B in my export. I don't want to copy manually all properties of A in the constructor of B. Some objects have more than 20 properties.
Most of the time changing the return-type from a class is a sign of a bad design. In particular it means that you should favour composition over inheritance.
Having said this what you actuall want is to map one class to another. You can do that yourself, e.g. like this:
class A
{
int MyProperty { get; set; }
}
class B
{
private readonly A a;
public B(A a) { this.a = a; }
}
Now you can easily implement your mapping:
class B
{
public string MyProperty
{
get => this.a.MyProperty.ToString();
set => { this.a.MyProperty = int.Parse(value); } // consider to check the value before conversion
}
}
This is just the basic idea. As your models can become huge and doing this mapping yourself therefor becomes pretty cumbersome, you'd best use some automatic mapper, e.g. AutoMapper for that.
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.
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.
I am designing a c# class and would like to know if my design is right.
abstract class PersonBase
{
public string Name { get; set; }
public PersonBase Parent { get; set; }
public List<PersonBase> Children { get; set; }
}
class Person : PersonBase
{
//public override List<Person> Children { get; set; }
public Person()
{
Children = new List<PersonBase>();
}
public void Add(Person child)
{
child.Parent = this;
Children.Add(child);
}
}
test code:
private void button1_Click(object sender, EventArgs e)
{
Person parent = new Person();
parent.Name = "parent";
Person child = new Person();
child.Name = "child1";
child.Add(new Person() { Name = "grandchild1" });
parent.Add(child);
}
It works as expected. I am able to access the parent children objects from anywhere in the hierarchy. My concern is it looks recursive or circular reference (can't find the right word here).
Here is what I did finally:
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public List<Person> Children { get; private set; }
public Person()
{
Children = new List<Person>();
}
public void AddChild(Person child)
{
if (child == this) { return; }
if (Children.Contains(child)) { return; }
child.Parent = this;
Children.Add(child);
}
}
Like #LukeH asked your break out of BasePerson and Person do not make sense. This will work just fine.
public class Person
{
public string Name { get; set; }
public Person Parent { get; set; }
public IList<Person> Children { get; private set; }
public Person()
{
Children = new List<Person>();
}
public void Add(Person child)
{
child.Parent = this;
Children.Add(child);
}
}
If you are going to have different kinds of Person then you might want to break you stuff out into an Interface if there is not inherited logic and an abstract class if you want to provide some default logic.
EDIT: Adding expressed issues from Danny
It could become a problem if you used child.Add(Me or MyParent or ancestor). Then it would be an endless loop of references. You might want to add code in the Add method to prevent improper usage so a 'Person' can not add itself or it's parents as a child.
The base class seams redundant, also, you are assuming children is not null and assigning in constructor, yet it has a public setter.
Change children's setter to private or protected and don't worry about circular reference - just mark parent property with an attribute to prevent it from being serialized.
//Declare and initialize Person a, b, c;
a.Add(c);
b.Add(c); // Now a thinks c is a child, but c does not think a is a parent!
You need some sort of validation, perhaps that c doesn't already have a parent, or set the parent/child only in a Parent.CreateChild method. Or allow it to have multiple parents.
(Also, I would declare the method AddChild, since that's what it's doing. And also pay attention to the design considerations from other commenters.)
Perhaps this:
class Person
{
public string Name { get; private set; }
public Person Parent { get; private set; }
public IList<Person> Children { get; private set; }
private Person() {} // Private constructor
public static Person CreatePersonNoParent(string name){*implementation elided*};
public Person CreateChild(string name)
{
Person child = new Person { Name=name, Parent=this };
this.Children.Add(child);
return child;
}
}
I have to classes, Father and Child (by example)
A snippet of my implementation
Class Father.cs
public class Father
{
public int Id { get; set; }
public string Name { get; set; }
public List<Child> Children { get; set; }
public Father()
{
}
}
Class Child.cs
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Child()
{
}
}
I'am trying to do something like this
Father f = new Father();
f.Children[0]; // ok
f.Children[1]; // ok
f.Children["John"]; // Duh!
I now, its wrong, i need to implement something in Child Class, i tryed this
public Child this[string name]
{
get
{
return this;
}
}
But this doesnt work.
How can i implement this feature for my class Child?
A List<T> doesn't have a string indexer; you could add one to the Father class, but the usage will be:
var child = parent["Fred"];
(no .Children)
For the indexer itself: Try (in the indexer):
return Children.FirstOrDefault(c=>c.Name==name);
To get an indexer on the list itself, you would have to create a custom list type and add the indexer there.
IMO, a method may be clearer (on Father):
public Child GetChildByName(string name) {...}
Or you can set it up like this:
public class Father
{
public int Id { get; set; }
public string Name { get; set; }
public Children Children { get; set; }
public Father()
{
}
}
public class Children : List<Child>
{
public Child this[string name]
{
get
{
return this.FirstOrDefault(tTemp => tTemp.Name == name);
}
}
}
public class Child
{
public int Id { get; set; }
public string Name { get; set; }
public Child()
{
}
}
Then you call it how you want.
In father class, you could write following code:
public Child this[string name]
{
get
{
return Children.Where(c => c.Name == name);
}
}
and use it like:
Father f = new Father();
f.Children[0]; // ok
f.Children[1]; // ok
f["John"]; // ok!
You are treating the List of Children like a Dictionary (Dictionaries can be accessed by key). Just change your List to a Dictionary and set the string to be the Child's name.
You could make the Children List into an OrderedDictionary so that you can reference it by index or key and then add the objects with the name as the key. Just so you know though, any of these options can run into issues if you have multiple children with the same name.