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.
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!";
I have the following classes:
//some base class
public abstract class MyObject<T>{
public static T FromObject(object anotherObject){
var t = Activator.CreateInstance<T>();
// some reflection logic here
return t;
}
}
public class Product: MyObject<Product>{
}
public class ProductCart: MyObject<ProductCart>{
public ICollection<Product> Products{get;set;}
}
public class Basket: ProductCart{
public int BasketId{get;set;}
}
public class Order: ProductCart{
public int OrderId{get;set;}
}
So now I could build my model like this:
var products = serviceContext.Products.Select(Product.FromObject).ToList(); // no problem here
var basket = Basket.FromObject(serviceContext.Basket); // problem is here - instance of ProductCart is returned
var order = Order.FromObject(serviceContext.Order); // same problem, instance of ProductCart
Is there a way somehow to solve it and get converted Basket and Order instead of base ProductCart?
The goal is:
var basket = Basket.FromObject(serviceContext.Basket); // return instance of Basket inherited from ProductCart
Thanks for helping.
If you can change the class definitions, you can pass along the type to ProductCart, like so:
public class ProductCart<T> : MyObject<T> { }
public class Basket : ProductCart<Basket> { }
public class Order : ProductCart<Order> {}
In your definition you tell Basket.FromObject to explicitly return ProductCarts (by inheriting from MyObject<ProductCart>).
And if you're unable to change the inherit tree, you can choose to hide the original method (or place it in a factory):
public class Basket : ProductCart
{
public int BasketId { get; set; }
public Basket FromObject(object anotherObject)
{
return MyObject<Basket>.FromObject(anotherObject);
}
}
That's because Basket is a MyObject<ProductCart>, and not a MyObject<Basket>.
If you don't want to redefine your hierarchy, you should define the return type of the static method according to the object you pass, like in this example:
using System;
public abstract class MyObject<T> {
public static TOtherObject FromObject<TOtherObject>(TOtherObject anotherObject) where TOtherObject : MyObject<T> {
var newOtherTypeInstance = Activator.CreateInstance<TOtherObject>();
// some reflection logic here
return newOtherTypeInstance;
}
}
public class ProductCart : MyObject<ProductCart> {
}
public class Basket : ProductCart {
public int BasketId { get; set; }
}
public class Order : ProductCart {
public int OrderId { get; set; }
}
class Program {
static void Main(string[] args) {
Order o = new Order();
var basket = Basket.FromObject(o);
}
}
Of course, at this point the actual implementation of the comment "some reflection logic here" could get much more complicated :)
I have troubles with finding the correct words for this question, so I will try to show you with some code what my problem is.
I have a parent class, which looks like this:
public class ParentClass {
public Guid ParentId { get; }
public int ParentProperty { get; set; }
public List<ParentClass> ParentList { get; set; }
public ParentClass() {
this.ParentId = Guid.NewGuid();
}
}
It is rather simple: It got an ID, a few properties and a List containing elements of itself.
Now I am creating a child class, which looks like this:
public class ChildClass : ParentClass {
public string ChildProperty { get; set; }
public ChildClass() : base() {
this.ParentList = new List<ChildClass>();
}
}
This one got one extra property and a constructor, which contains the problem. I can't initiate a List into the declaration of the List.
I can't just do the declaration of the list in the child class, as I need it in the parent class when I am using it.
What is the best way to solve this problem?
You should use an interface that point both classes (ParentClass as well as ChildClass).
A generic type having a certain type-parameter is a "new" type: So List<ChildClass> and List<ParentClass> are different types.
I think the easiest way to achieve what you want is to initiate the list with its base type : List<ParentClass>
public class ChildClass : ParentClass
{
public string ChildProperty { get; set; }
public ChildClass() : base() {
this.ParentList = new List<ParentClass>();
}
public void AddSomething()
{
// this is ok :
this.ParentList.Add(new ChildClass());
}
}
This could work only if the type List<T> were covariant in T, also known as "out T". However, it is not, and cannot be.
The type List<> allows Add, Insert and others, and so it is not semantically covariant.
In C# (as of currently), class types cannot be made covariant. That is not supported. Only interface and delegate types can be made covariant (or contravariant) in their generic parameters.
The closest we get is IReadOnlyList<out T> which is covariant, so:
IReadOnlyList<ParentClass> parentList = new List<ChildClass>();
is allowed. However, it is not helpful in your case.
public class ParentClass<TChild> where TChild : class
{
public List<TChild> ParentList { get; set; }
public Guid ParentId { get; set; }
public int ParentProperty { get; set; }
public ParentClass()
{
ParentId = Guid.NewGuid();
ParentList = new List<TChild>();
}
}
public class ChildClass : ParentClass<ChildClass>
{
public string ChildProperty { get; set; }
}
Create method with access to similar named field, but different types of object without inheritance in c#.
For ex. I have 2 Classes:
public class MyClass1
{
public int Id { get; set; }
}
public class MyClass2
{
public int Id { get; set; }
}
And I need to create method and pass to it instance of each Classes:
DoStuff(new MyClass1());
DoStuff(new MyClass2());
And Method will be like this:
private void DoStuff<T>(T obj)
{
int i = obj.Id(); // here is the problem
}
Yes, problem is, that obj can't resolve Id. Solution simple - create RootClass with Id property, and use public class MyClass1: RootClass... , but I can't do this.
Question is: Can I use line like int i = obj.Id(); without creating RootClass?
Edit: I need answers like: No, because.... or Yes, do this.....
This is typically why interfaces exist: describe a common contract, but with no relationship between the classes.
I would suggest you to create this interface
public interface IHasId {
int Id { get; set; }
}
public class MyClass1 : IHasId
{
public int Id { get; set; }
}
public class MyClass2 : IhasId
{
public int Id { get; set; }
}
...
private void DoStuff<T>(T obj)
where T : IHasId // constraint my be moved to the class declaration
{
int i = obj.Id();
}
Creating this interface will let you avoid introducing a root class, which may be not desired if the classes has no root behavior.
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.