Inheritance : How copy an object from master class to child class - c#

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.

Related

Making members in subclasses readonly

Let's say I have the class A with member int number which has a getter and a setter.
Then I make a subclass of A and call it B. Now in the class B I wish to keep the member number, but in this class I want to impose the restriction that number is read-only. How can I do this?
The need for that is usually a hint that your design is not optimal (as it violates the Liskov substitution principle). Therefore, C# does not really support it. However, here are two ways to kind of implement it:
(1) Hide the property in the descendent and provide a new property that replaces the getter of the base class. But this does not really protect the property, since you can just cast to the base class:
class A
{
public int Number { get; set; }
}
class B : A
{
public new int Number
{
get { return base.Number; }
}
}
B b = new B();
// b.Number = 42; // This does not work.
A a = b;
a.Number = 42;
Console.WriteLine(b.Number); // == 42. Oops.
(2) Override the setter with an exception throw. But a wrong usage now causes a runtime error instead of a compiler error which is not nice. Consider adding a bool CanSetNumber property to the base (.NET does something similar with Stream.CanSeek and Seek).
class A
{
public virtual int Number { get; set; }
}
class B : A
{
public override int Number
{
get { return base.Number; }
set { throw new InvalidOperationException("B.Number is readonly!"); }
}
}
B b = new B();
b.Number = 42; // BAM!
I agree with Sebastian's answer. Another option to consider is to use a common interface instead of direct inheritance
public interface IHasNumber
{
int Number { get; }
}
public class A : IHasNumber
{
public int Number { get; set; }
}
public class B : IHasNumber
{
public int Number { get; }
}
If you want to share the values then you must encapsulate A in B.
public class B : IHasNumber
{
public B(A data) { this.Data = data; }
private A Data { get; private set; }
public int Number { get { Data.Number; } }
}
To be used as
{
var A = new A();
A.Number = 100; // ok
var B = new B(A);
B.Number = 200; // error
Console.WriteLine(B.Number); // prints 100
}

Handling class specific properties in a generic method

I'm still wrapping my head around generics and have run up against a challenge that I want to work through correctly. If I have a few classes defined like so:
public abstract class DocBase {
public long ID { get; set; }
public string Description { get; set; }
public long DocumentID { get; set; }
public string DocumentDate { get; set; }
...snipped...
}
public class AppDoc : DocBase {
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
public class OtherDoc : DocBase {
public string D { get; set; }
public string E { get; set; }
public string F { get; set; }
}
I have a class that will be used to retrieve these documents
public class Repo<T> where T : DocBase, new()
This class will contain a method:
public List<T> GetDocs()
In this method I want to be able to access the properties defined in the derived classes (so in AppDoc: A,B,C and in OtherDoc: D,E,F). But if I declare a new object like so:
var doc = new T();
At design time I only have the properties available in the base class (DocBase) and not the dervied classes (AppDoc and OtherDoc). How do I get to properties A, B, C, D, E and F?
EDIT: To elaborate on my "how do I get to..." a bit. I need to populate properties A, B, C, D, E and F within the GetDocs() method from a list of results I get back from a database.
public List<T> GetDocs(){
var results = someService.GetMyDocuments();
var documents = new List<T>();
foreach(IRepositoryRow row in results) {
var newDoc = new T();
newDoc.A = row.GetProperty("AFromDatabase").ToString();
newDoc.B = row.GetProperty("BFromDatabase").ToString();
documents.Add(newDoc);
}
return documents;
}
That's generally flawed. Your design would break the laws of polymorphism entirely, because you want access to a a derived class' properties where only base class information is available.
So the question is not How can I ... but What's wrong with my design?.
Edit:
OR Mappers (e.g. Entity Framework or NHibernate) can handle such polymorphism scenarios automatically for you. I suggest you take this route.
It depends what are you wanting to do with those properties.
If you are manipulating them (eg populating them or calculating thigns based on them) then an abstract method on DocBase like DoStuff could then be called safely on your T and it could do whatever you want with the properties.
If you want to do different things depending on what the object is then that's not really being very generic and you probably want to rethink things a bit, preferably to having abstract or virtual methods that you can call on the objects.
Some sample code based on what you've put in your question:
public abstract class DocBase {
...
public abstract void LoadProperties(IRepositoryRow row);
...
}
public List<T> GetDocs(){
var results = someService.GetMyDocuments();
var documents = new List<T>();
foreach(IRepositoryRow row in results) {
var newDoc = new T();
newDoc.LoadProperties(row);
documents.Add(newDoc);
}
return documents;
}

loop through a collection of classes and recognize them for adding a new one

I've got a set of classes with propperties and a main class which has lists of the set of classes.
public class MainClass
{
public List<ClassA> listA {get;set;}
public List<ClassB> listB {get;set;}
public List<ClassC> listC {get;set;}
public object[] loop = {listA, listB, listC};
}
class ClassA
{
public Guid id {get;set;}
public string text {get;set;}
public int number {get;set}
public status {get;set;}
public object[] loop = {id, text, number};
}
class ClassB
{
public Guid id {get;set;}
public string text {get;set;}
public Image pic {get;set}
public status {get;set;}
public object[] loop = {id, text, pic};
}
class ClassC
{
public Guid id {get;set;}
public byte[] data {get;set;}
public DateTime date {get;set;}
public status {get;set;}
public object[] loop = {id, data, date};
}
public enum status
{
nothing=0, instert=1, delete=2, edit=3
}
Situation has changed since yesterday but still, i'd like to index my class, my idea was by adding this line:
public object[] loop = {listA, listB, listC};
to MainClass, archieving this goal, after changing the whole thing to an non static class it seems forbidden. also when i was trying this with a static class i cant adress my lists directly. could this be done any how?
finaly i want to adress a specific property inside the list like this:
MainClass mc = new MainClass();
DateTime dt = mc.loop[2][5].loop[2];
even if it would be nicer to do this without the loop property, like:
DateTime dt = mc[2][5][2];
how i want to loop it finaly:
for(int i=0; i<mc.loop.count(); i++)
{
for (int j=0; j<mc.loop[i].Count(); i++)
{
switch(mc.loop[i][j].loop[3])
{
case: delete
doSomething1(mc.loop[i][j])
case: insert
doSomething2(mc.loop[i][j])
case: edit
doSomething3(mc.loop[i][j])
default
break;
}
}
}
As I've written in my comment, you should simply go for a Object-Relational Mapping framework, since you are obviously trying to abstract the mapping from your domain into the database.
That being said, you can generalize the whole thing using Reflection. Provided that you don't intend to add complex mapping rules, you would have something similar to:
foreach (var propertyInfo in myClass.GetType().GetProperties())
{
var name = propertyInfo.Name;
var value = propertyInfo.GetValue(myClass);
// do stuff
Console.WriteLine("Value of {0} is {1}", name, value ?? "null");
}
A proper ORM does a lot more than this. If allows you to define specific mapping rules for each property. Nested objects and automatic mapping of one-to-many relations. It does lots of complex caching to avoid performance penalty associated with reflection (and more important, database access). It allows lazy access to the database by deferring queries until data is needed. It tracks which properties are changed and automatically updates them. And all that by including a reference to a library, spending a day or two looking at examples (and asking stuff on Stack Overflow) and writing a mapping configuration file.
Or, you can define mappings through code to get full intellisense and better type safety:
// fluent nhibernate example
public class CatMap : ClassMap<Cat>
{
public CatMap()
{
// define which properties are going to be saved, and how
Id(x => x.Id);
Map(x => x.Name).Length(16).Not.Nullable();
Map(x => x.Sex);
References(x => x.Mate);
HasMany(x => x.Kittens);
}
}
What you are doing right now is a maintenance nightmare. You are enforcing a rule where each data class needs to expose its properties as an object array (and think about how you would update their values this way). Also, you lose all type safety because you end up with plain objects. The only way for you to know which property you are accessing is by the index of the loop array, meaning you are going for lots of if conditions and magic numbers all over your code. As an exercise of how things shouldn't be done, it's fine, but don't allow this to end up in production code or you will spend countless hours fixing bugs and changing code to add new functionality.
try something like this:
MainClass mc = new MainClass();
DateTime dt = ((ClassA) mc.loop[2]).date;
Still I am not sure what you really want and what are all those indexes for...
1) to discard the loop variable you can create class indexer like this
private object[] loop = {id, text, number};
public int this[int index]
{
get { return loop[index]; }
set { loop[index] = value; }
}
2) to be able to retrieve the variables you would probably have to cast them from object to their actual types to be able to use their capabilities. it is still unpractical.
DateTime dt = ((DateTime) ((ClassA)mc[0]) [2]);
Ok, not sure what you are doing but how about this
public enum Status
{
Nothing = 0,
Insert,
Delete,
Edit
}
public abstract class Searchable
{
public virtual Guid Id { get; set; }
public virtual Status Status { get; set; }
protected internal abstract IEnumerable SearchableProperties { get; }
}
public class ClassA : Searchable
{
public string Text { get; set; }
public int Number { get; set; }
protected internal override IEnumerable SearchableProperties
{
get
{
yield return Text;
yield return Number;
}
}
}
public class ClassB : Searchable
{
public string Text { get; set; }
public Image Pic { get; set; }
protected internal override IEnumerable SearchableProperties
{
get
{
yield return Text;
yield return Pic;
}
}
}
public class ClassC : Searchable
{
public byte[] Data { get; set; }
public DateTime Date { get; set; }
protected internal override IEnumerable SearchableProperties
{
get
{
yield return Data;
yield return Date;
}
}
}
Then you can write your main class like this,
public class Searchables
{
public List<ClassA> ListA { get; set; }
public List<ClassB> ListB { get; set; }
public List<ClassC> ListC { get; set; }
public void SearchContents(Action<Status, Searchable, object> visitor)
{
SearchContent(this.ListA, visitor);
SearchContent(this.ListB, visitor);
SearchContent(this.ListC, visitor);
}
private static void SearchContent(
IEnumerable<Searchable> searchees,
Action<Status, Searchable, object> visitor)
{
foreach (var searchee in searchees)
{
visitor(searchee.Status, searchee, searchee.Id);
foreach (var property in searchee.SearchableProperties)
{
visitor(searchee.Status, searchee, property);
}
}
}
}
Then all you have to do is write the visitor ...
var mainClass = new Searchables();
....
mainClass.SearchContent((status, searchee, property) =>
{
switch(status)
{
case Status.Delete:
// DoSomthing1 ...
break;
}
});
but, that bit is not in your question.

Default object implementation

I want to implement default object pattern for my all classes in the inheritance tree. I am doing as shown below.
namespace test
{
public class Record
{
public int ID { get; set; }
}
public class StudentRecord : Record
{
public string StudentID { get; set; }
}
public class DriverRecord : Record
{
public string DLNumber { get; set; }
}
public class client
{
public static void Main()
{
StudentRecord st = StudentRecord.Default;
DriverRecord dr = DriverRecord.Default;
}
}
}
I want the default property or method to initialize all the class level properties to their defaults and I don’t want to repeat the implementation for each class. I just want to write on Record (base ) class . Can you provide some suggestions on this?
What you’re looking for is exactly what constructors are for. A constructor can call an inherited base constructor, so you need to do the base initialisation in only one place. Sometimes the basic functionality really does what you need :)
public class Record
{
public int ID { get; set; }
public Record()
{
// ... do general initialisation here ...
}
}
public class StudentRecord : Record
{
public string StudentID { get; set; }
public StudentRecord()
: base() // This calls the inherited Record constructor,
// so it does all the general initialisation
{
// ... do initialisations specific to StudentRecord here ...
}
}
public class client
{
public static void Main()
{
// This calls the constructor for StudentRecord, which
// in turn calls the constructor for Record.
StudentRecord st = new StudentRecord();
}
}
The Record class can only set the properties which are inherited by StudentRecord and DriverRecord. If you want to set class-specific properties to their default values you have to override the method (I would make a method) and do something like this (for StudentRecord ):
public void override Initialize()
{
base.Reset();
this.StudentId = 0;
}
HTH
You don't have any "class level properties", i.e. static properties, in your code sample. The properties you do have (the instance properties) are already initialized to their defaults -- 0 for integers, null for references, etc.
If you want to define your own defaults -- perhaps ID should default to -1 until you save, and the strings should default to "" -- then that's exactly what constructors are for:
public class Record
{
public Record() { ID = -1; }
public int ID { get; set; }
}
public class StudentRecord : Record
{
public StudentRecord() { StudentID = ""; }
public string StudentID { get; set; }
}
// etc.
If you want something different from either of those, you'll have to explain what you're looking for.
I think Null Object Pattern is what you need.

Interfaces property name differs from class to class

Here`s the question.
public abstract class A {}
public class B:A
{
public TypeF FieldB;
}
public class C:A
{
public TypeG FieldC;
}
public class TypeF:A { }
public class TypeG:A { }
I want to have interface ex: ITypeFG and to implement it in B and C BUT to have properties names FieldB and FieldC
interface ITypeFG
{
public A FieldFG; //But i want to have names TypeF in A and TypeG in B
}
Can this be done?
Thanks.
explicit interface implementation:
public class B : A, ITypeFG
{
public TypeF FieldB { get; set; } // please don't expose public fields...
A ITypeFG.FieldFG { get { return FieldB; } }
}
public class C : A, ITypeFG
{
public TypeG FieldC { get; set; }
A ITypeFG.FieldFG { get { return FieldC; } }
}
Note that if the interface has a setter, you'll need to cast:
public class B : A, ITypeFG
{
public TypeF FieldB { get; set; }
A ITypeFG.FieldFG { get { return FieldB; } set { FieldB = (TypeF)value; } }
}
public class C : A, ITypeFG
{
public TypeG FieldC { get; set; }
A ITypeFG.FieldFG { get { return FieldC; } set { FieldC = (TypeG)value; } }
}
Two points:
Interfaces in C# can't have fields, but they can have properties.
The desired feature isn't sensible: if clients would always have to know the "specific" name of the implemented interface-property to interact with an implementation, then it isn't much of an interface is it - it's little more than a marker.
As Marc Gravell suggests, a decent workaround is to use explicit implementations. If the client has a reference to the implementing object typed as the interface, they can use the "general" name of the property. If they have a specific reference (i.e. typed as the implementing type) , they can use the "specific" name (and won't be confused by the general name since they won't see it on IntelliSense, for example).
Sounds like you should treat the field names as data along with A. That way you can keep a common interface and only vary the content of what is returned:
class Data
{
public string Name {get;set;}
public A Value {get;set;}
}
interface ITypeFG
{
Data Field {get;}
}
class B : A, ITypeFG
{
public Data Field
{
get
{
return new Data {Name = "TypeF", Value = FieldB};
}
}
}
class C : A, ITypeFG
{
public Data Field
{
get
{
return new Data {Name = "TypeG", Value = FieldC};
}
}
}

Categories

Resources