Hey guys I recently started learning C# using microsoft .Net Tutorials.
I'm stuck at "Classes and Objects" Lesson.
At the end of the each lesson we have a little "homework" to do.
I need to write a program that prints out addresses for people and companies using three different classes (Person, Copmany, Address). I need to add them to collection and loop through, printing out the address for each company or person.
Here is the LINK (at the end of the page there is an example how the program should look like.
I'm not really sure how am I suppose to achieve this. Can someone please help me understand. This is what I come so far:
public class Address
{
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public override string ToString()
{
return $"{StreetAddress}, {City}, {PostalCode}, {Country}";
}
public Address()
{
StreetAddress = "Main123";
City = "SomeTown";
State = "OH";
PostalCode = "12345";
Country = "United States";
}
}
public class Person : Master
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address ShippingAddress { get; set; }
public Person(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
ShippingAddress = new Address();
}
public override string ToString()
{
return $"{FirstName} {LastName} {ShippingAddress}\n";
}
}
public class Company : Master
{
public string Name { get; set; }
public Address ShippingAddress { get; set; }
public Company(string name)
{
Name = name;
ShippingAddress = new Address();
}
public override string ToString()
{
return $"{Name} {ShippingAddress}\n";
}
}
public class Master
{
public static List<Master> data = new List<Master>();
public static void Coll(Master master)
{
data.Add(master);
data.ForEach(Console.WriteLine);
}
}
class MainClass
{
public static void Main(string[] args)
{
Person John = new Person("John", "Smith");
Master.Coll(John);
}
}
If you have already reached the end of your tutorial, then it means that you have read the section about Inheritance and Polymorphism.
Please read this section again carefully.
If your task is: printing out the address for each company or person
Have a look on what the tutorial says about the ToString method:
Note that you can override the ToString method on any class where it will make sense to display string data related to an instance of the class.
So you first step would be to give the class Address the ability to display it's content, by overriding the ToString method.
You second step would be to use inheritance and create a super class which can be inherited by your 2 classes Person and Company. As it is done in the tutorial with the class Shape.
This will allow you to to add them to [a single] collection (as you wrote in your request).
Try to combine these steps and if you still have questions drop me a comment.
(Please keep rereading the tutorial, all the necessary information is in there, you just have to combine the different parts). Good fortune!
EDIT:
After you have edited your code, the next steps would be to give your classes Person and Company the ability to display information about themselves. Meaning you should override the ToString method also there.
One tip : you can use the ToString method of the class Address to display the details of the ShippingAddress. No need to write the details again ;) If you include the variable in the extrapolated string $"... the ToString method will be called implicitly and display all the details:
$"{ShippingAddress}"
One problem with your Coll method is that it is using a local variable List<Master> data as storage. This variable will cease to exist when the compiler returns from the method. Another problem is that in each call you create a new List making it impossible to store more than 1 element. What you can do is to make it a static variable inside the Master class. So that every time you add an item it will stay in memory and can be accessed later on.
You can also make the method static since it does not really require an object of type Master to be called (it does not access any class properties)
public class Master
{
public static List<Master> data = new List<Master>();
public static void Coll(Master master)
{
data.Add(master);
data.ForEach(Console.WriteLine);
}
}
You can call it like this then:
Person John = new Person("John", "Smith");
Master.Coll(John);
This is fairly straight forward. You can do it using interfaces or polymorphism.
You need put objects into collection, and iterate through all of them.
entityList = new List<IPrintable>();
foreach(var entity in entityList)
{
entity.PrintAddress();
}
To achieve this, you need to use common interface for both classes;
internal interface IPrintable
{
void PrintAddress();
}
You need to implement this interface in both classes.
public class Person : IPrintable
{
public void Print()
{
Console.WriteLine("Person's address is {0}", ShippingAddress.ToString());
}
}
public class Company : IPrintable
{
public void Print()
{
Console.WriteLine("Company's is {0}", ShippingAddress.ToString());
}
}
public class Address
{
public string ToString()
{
return string.Format(" Street: {0}, {1}, {2}, {3}, post code{4}, {5}", StreetAddress, City, State, PostalCode, Country);
}
}
Instead of having common interface you can make abstract base class, which will hold ShippingAddress field and have virtual method Print() without implementation. Then this base class will be type you use in List class
var entitylist = newList();
public abstract class ShippableEntity
{
private Address _Address;
private ShippableEntity(Address address)
{
_Address = address;
}
public abstract void Print();
public Address ShippingAddress { get { return _Address; } }
}
Then you inherit this class in Person and Company and implement Print method in concrete classes.
Then you can do:
entitylist.Add(new Person(....));
entitylist.Add(new Company(....));
and do the same thing with foreach as with interface.
You need to call base class constructor!
public class Person : ShippableEntity
{
public Person(Address address)
: base(adress)
{
}
}
I hope this helps.
Related
I have the following issue
Here is third party class which we are used(so i cannot change it)
public class ThirdPartyEmployee
{
public string F_Name { get; set; }
public string L_Name { get; set; }
public DateTime Date_of_birth { get; set; }
public string Telephone1 { get; set; }
public string Telephone2 { get; set; }
public string Position { get; set; }
//..... and so on
}
Also we have our own smaller and better Employee class
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string MobileTelephone { get; set; }
}
Sometimes we need to convert third party class to our own. There is extension method for it
public static class ThirdPartyExtensions
{
public static Employee ConvertTo(this ThirdPartyEmployee thirdPartyEmployee)
{
var result = new Employee();
result.FirstName = thirdPartyEmployee.F_Name;
result.LastName = thirdPartyEmployee.L_Name;
result.MobileTelephone = thirdPartyEmployee.Telephone1;
return result;
}
}
Now about the issue. If somebody consider to add some other properties to Employee class he\she can forget to change ConvertTo method. How we can avoid it ? Ideally i would like to have some compilation errors ...
Any suggestions ?
If your Employee class is just a container, there's one simple approach:
public class Employee
{
private readonly string firstName;
public Employee(string firstName)
{
this.firstName = firstName;
}
}
Now your conversion method has no choice but to pass all the arguments, so you get a compiler error when the conversion method isn't updated.
Of course, this still isn't foolproof - if you also care about changing the arguments, this doesn't help much.
And now that we have Roslyn, with great integration in Visual Studio, you can actually make your own compiler errors using a Roslyn analyzer. If you're not afraid of getting your hands dirty, this would be a great opportunity to show how useful something like that can be. Sadly, it's not very easy to use right now, and needs "the right kind of thinking" to be wielded well. It will allow you to make rules like "a class conversion extension method must assign all properties in the resulting class", for example.
You can not create a compilation error with standard means. There may be Visual Studio plugins that allow you to do that.
But it may not be necessary: You could change the CopyTo method so that instead of hardcoding all the properties to be copied, it uses reflection to obtain a list of all public properties to copy.
Example code to start with:
FieldInfo[] myObjectFields = type.GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (FieldInfo fi in myObjectFields)
{
i.SetValue(destination, fi.GetValue(source));
}
To handle different property names: You could introduce an attribute which allows you to specify which property of ThirdPartyEmployee translates to which property of Employee. This can also be evaluated using reflection.
Example:
public class Employee
{
[CopyFromThirdPartyEmployee("F_Name")]
public string FirstName { get; set; }
[CopyFromThirdPartyEmployee("L_Name")]
public string LastName { get; set; }
[CopyFromThirdPartyEmployee("Telephone1")]
public string MobileTelephone { get; set; }
}
You could have the CopyTo method throw an exception when it finds a public property which does not have the required mapping attribute. That way you could be sure that every property also has the attribute - but that would be a runtime error, not a compile time error.
Another approach be to simply make Employee a wrapper for ThirdPartyEmployee:
public class Employee
{
private ThirdPartyEmployee _baseEmployee;
public Employee() { _baseEmployee = new ThirdPartyEmployee(); }
public Employee(ThirdPartyEmployee e) { _baseEmployee = e; }
public string FirstName
{
get { return _baseEmployee.F_Name; }
set { _baseEmployee.F_Name = value; }
}
...
}
That way you'd notice that if you can't access a property you haven't implemented it. The downside is that every employee would then be based on a ThirdPartyEmployee.
You can do this with the help of reflection, but dictionary for names mapping is needed:
public static class ThirdPartyExtensions
{
static Dictionary<string, string> map;
static ThirdPartyExtensions()
{
map = new Dictionary<string, string>{ {"F_Name", "FirstName"} /*and others*/};
}
public static Employee ConvertTo(this ThirdPartyEmployee thirdPartyEmployee)
{
var result = new Employee();
if(map.Count < typeof(Employee).GetProperties().Count())
throw new Exception("Forget to add mapping for new field!");
foreach(var prop in typeof(ThirdPartyEmployee).GetProperties())
if(map.ContainsKey(prop.Name))
{
var temp = typeof(Employee).GetProperty(map[prop.Name]);
temp.SetValue(result, prop.GetValue(thirdPartyEmployee));
}
return result;
}
}
Using Roslyn analyzers it's possible to produce compile-time (and IntelliSense) errors that go beyond the scope of the compiler. Here's a very simple implementation of an analyzer that checks that all the properties of a type returned by a method have been assigned. It doesn't take into account control flow (e.g. if).
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class AssignAllPropertiesAnalyzer : DiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor Rule = new DiagnosticDescriptor("AssignAllPropertiesAnalyzer",
"All properties must be assigned.", "All properties of the return type must be assigned.", "Correctness",
DiagnosticSeverity.Warning, isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule);
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeMethod, SyntaxKind.MethodDeclaration);
}
private static void AnalyzeMethod(SyntaxNodeAnalysisContext context)
{
var methodNode = (MethodDeclarationSyntax)context.Node;
var methodSymbol = context.SemanticModel.GetDeclaredSymbol(methodNode);
if (methodSymbol.GetReturnTypeAttributes().Any(x => x.AttributeClass.Name == "AssignAllPropertiesAttribute"))
{
var properties = methodSymbol.ReturnType.GetMembers().OfType<IPropertySymbol>().Where(x => !x.IsReadOnly).ToList();
foreach (var assignmentNode in methodNode.DescendantNodes().OfType<AssignmentExpressionSyntax>())
{
var propertySymbol = context.SemanticModel.GetSymbolInfo(assignmentNode.Left).Symbol as IPropertySymbol;
if (propertySymbol != null)
{
properties.Remove(propertySymbol);
}
}
if (properties.Count > 0)
{
var diagnostic = Diagnostic.Create(Rule, methodSymbol.Locations[0]);
context.ReportDiagnostic(diagnostic);
}
}
}
The analyzer assumes an attribute named AssignAllProperties is applied to return type of a method. In the following example, ~~~~~~ marks the location where analyzer would produce a diagnostic.
class A
{
public string S { get; set; }
}
[return: AssignAllProperties]
public static A Create()
~~~~~~
{
return new A();
}
An analyzer can be installed both as a VSIX and as a NuGet package. I would recommend always using the NuGet approach - it would apply the analyzer for everyone consuming the code and would allow you to change the severity (e.g. to error), thus failing the compilation. To get started with building an analyzer library, install the Roslyn SDK and create an Analyzer with Code Fix C# project.
You cannot generate a compile error for that, but... I would move the conversion method to the Employee class. I suggest to avoid Extension methods that are dependend on data (like properties from other classes)
public class Employee
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string MobileTelephone { get; set; }
public static Employee From(ThirdPartyEmployee employee)
{
var result = new Employee();
result.FirstName = thirdPartyEmployee.F_Name;
result.LastName = thirdPartyEmployee.L_Name;
result.MobileTelephone = thirdPartyEmployee.Telephone1;
return result;
}
}
This way you keep all functionality in the right class/file and it is clear for others if they add properties.
I am making a console test with C#.
Actually I have never used of C# but VB.Net. I want to create arrays for one-to-many relationship.
My one is 'A Student' has 'Name','Sex',...,'Courses Taken'.
A Student would take many course, each course has a Title and Included Subject. Each subject has Name, Description and Point.
Like this.
Student
- Name - Sex - Courses Taken
Take Courses
- Course Title - Subject Included
Subject
- Subject Name [Math] [MVC]
- Subject description [Advance] [Building Website]
- Subject Point [6.9] [5.6]
I want to store each entity in Arrays but I don't know how to connect subjects/courses to each Students. And how can I get Student who attending Math or MVC. Because every students can have more then more course/ more than one subjects.
You'll want to create classes to describe your different objects.
class Student
{
string Name { get; set; }
Gender Sex { get; set; } // write an enum for this
IEnumerable<Course> CoursesTaken { get; set; }
}
class Course
{
string Title { get; set; }
Subject Subject { get; set; }
}
class Subject
{
string Name { get; set; }
string Description { get; set; }
double Points { get; set; }
}
Using List to create enumerations of instances of these new types allow you to use LINQ to select or evaluate members of the list (nested for loops work as well):
// populate a list of students called studentList
//...
// use LINQ to select the students you want
var mathResults = studentList.Where(student => student.CoursesTaken.Any(course => course.Subject.Name == "Math"));
I feel like I've done with it in good way...
Pls check my code for my ques! ^^
I first made 3 classes as below..
class Students
{
public string StudentName;
public int StudSize;
public bool StudSex;
public List<Take_Courses> tcourses;
public Students() { }
public Students(string name, int size, bool sex, List<Take_Courses> tcourses)
{
StudentName = name;
StudSize = size;
StudSex = sex;
this.tcourses = tcourses;
}
}
and
class Take_Courses
{
public string classname;
public List<Arr_Courses> arr_Course;
public Take_Courses() { }
public Take_Courses(string classname, List<Arr_Courses> arr_courses)
{
this.classname = classname;
arr_Course = arr_courses;
}
}
class Arr_Courses
{
public string cosname;
public string cosdesc;
public float cospoint;
public Arr_Courses() { }
public Arr_Courses(string name, string description, float point)
{
cosname = name;
cosdesc = description;
cospoint = point;
}
}
I then initialized values in Main class as below;
Arr_Courses acos=new Arr_Courses();
Arr_Courses acos1=new Arr_Courses("Math","Advance Math1",9.5f);
Take_Courses cos=new Take_Courses();
Take_Courses cos_take1=new Take_Courses("Info Tech",new List<Arr_Courses>{acos1});
Students stu=new Students();
Students Stu1 = new Students("Milla", 22, true,new List<Take_Courses>{cos_take1});
I then make another List to be generated names of student and use for looping and assign each one to List.
I think some important part is this.
if (arr_stud[i].tcourses[j].arr_Course[k].cosname.Equals("Math"))
{
Math_Stud++;
MathStudents[i] = arr_stud[i];
}
I am sharing this if anyone needs something like this. Any ungraded codes is appreciated to be shared. Thanks so so.
I'm stuck in my inheritances bloating here:
First let me explain the premise of my problem.
My Model:
public class Person
{
[Key]
public int PersonId { get; set; }
[MaxLength(100)]
public string Name { get; set; }
}
public class SuperHero:Person
{
[MaxLength(100)]
public string SuperHeroName { get; set; }
public virtual ICollection<SuperPower> SuperPowers{ get; set; }
}
Now, I am trying to create my viewModels for my MVC website, I have those base classes that need to be inherited by all other viewmodel displaying/editing a Person/SuperHero:
public class BasePersonViewModel
{
public string Name { get; set; }
ctors()
}
public class BaseSuperHeroViewModel : BasePersonViewModel
{
public List<string> SuperPowers{ get; set; }
ctors()
}
Here is where I am stuck, I am trying to define only one ViewModel that could be used regarless of the base class and access property of Person and/or SuperHero (if the Person is a superhero). I've been pulling my hair out but so far only found a solution which i don't like:
Example:
public class SomeViewModel<T> where T : BasePersonViewModel
{
public BasePersonViewModel obj;
public DateTime BirthDate { get; set; }
public SomeViewModel(Person data) //: base(data)
{
if (data is SuperHero)
obj = new BaseSuperHeroViewModel (data);
else
obj = new BasePersonViewModel(data);
}
}
While this would work it's really not sexy to use. And on top of that, I could have another ViewModel that inherit from SomeViewModel as well.
Is there a cleaner way to achieve this?
Edit
My main goal is to be able to able to cast my SomeViewModel depending on the one of the baseclass. Let's say do something like in my Controller:
if myclass is SomeViewModel (of type SuperHero)
Exactly how you do it for Person/SuperHero db retrival/check
var data = context.Person.first(w=> w.Id==1)
if (data is SuperHero)
..
I would like this because I would like to use the same viewmodel let's say to list superhero and person, and just display slightly differently if it's a superhero
Edit 2
I was trying to avoid using the whole Model.Obj to be able to see it directly with the Model... But the more i think about it, the more I think this is not possible really... On top of that I would like to extend some other superHero specific properties in SomeViewModel (only if SomeViewModel is a superhero), that are not declared in the BaseSuperHeroModel one... Let's say in SomeViewModel I want the field 'ComesFromPlanet' only if superhero.
Edit 3
I thought about another way to do it, but it obviously creating various ViewModel.
For the most general case (all fields that are shared for all Person) I would keep my base:
public class BasePersonViewModel
{
public string Name { get; set; }
ctors()
}
I interface specific Person:
public Interface IBaseSuperHero
{
[MaxLength(100)]
public string SuperHeroName { get; set; }
public List<string> SuperPowers{ get; set; }
}
I would keep as well OtherViewModel like this:
public class SomeViewModel:BasePersonViewModel
{
Public datetime Birthdate {get;set;}
}
Then I would create a specific SomeviewModel for other Person inheritant and used interfaces to have old and new properties.
For example:
public class SomeViewModelSuperHero:SomeViewModel, IBaseSuperHero
{
public string OriginalPlanet {get;set;}
}
Is this a clean solution?
Sorry I'm sure I am not clear about this, but I try !
Thanks for your input and time.
I am trying to define only one ViewModel that could be used regarless of the base class and access property of Person and/or SuperHero (if the Person is a superhero)
Assuming you'd return default values for super-hero properties when the model is not a super-hero, you could do something like this:
public class PersonOrSuperHeroViewModel {
private Person person;
private SuperHero superHero;
public PersonOrSuperHeroViewModel(Person personOrSuperHero) {
if (personOrSuperHero is SuperHero) superHero = personOrSuperHero;
person = personOrSuperHero;
}
public IsSuperHero { get { return superHero != null; } }
... // super-hero properties only work when IsSuperHero == true
}
How about something like
public class Person {
public virtual BasePersonViewModel MainViewModel {
get { return new BasePersonViewModel(this);}
}
}
public class SuperHero : Person {
public override BasePersonViewModel MainViewModel {
get { return new BaseSuperHeroViewModel(this);}
}
}
So if all your people classes override the MainViewModel property to return the appropriate view, you don't need
public BasePersonViewModel obj;
public SomeViewModel(Person data) {
if (data is SuperHero)
obj = new BaseSuperHeroViewModel (data);
else
obj = new BasePersonViewModel(data);
}
Because you can have
public BasePersonViewModel obj;
public SomeViewModel(Person data) { obj = data.MainViewModel; }
which will work however many subclasses of person you have.
Following on from this question Good class design by example I have a follow-up one.
I want to create some collections that are owned by other objects. To recap, I have a Person class and I want the Person to be able to have one or more Addresses. So I thought I would create an Address class and an Addresses collection. Make sense? Here's my code so far
class Person
{
public Person(int SSN, string firstName, string lastName)
{
this.SSN = SSN;
FirstName = firstName;
LastName = lastName;
}
public int SSN { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
class Address
{
public Address(string line1, string postCode)
{
Line1 = line1;
PostCode = postCode;
}
public int ID { get; set; }
public string Line1 { get; set; }
public string PostCode { get; set; }
}
class Addresses : System.Collections.CollectionBase
{
public int Person { get; set; } // should this be of type Person?
public void Add(Address addy)
{
List.Add(addy);
}
public Address Item(int Index)
{
return (Address)List[Index];
}
public void Remove(int index)
{
List.RemoveAt(index);
}
}
How can I associate many addresses with a Person? I'd like to do something like this in Main:
Person p = new Person(123,"Marilyn","Manson");
Address a = new Address("Somewhere", "blahblah");
p.Addresses.Add(a);
I then want to be able to save the addresses to a database. Should I do Address.Save() or Addresses.Save() (or something else)?
How would I change my code to implement that? Thanks for looking.
If you want the addresses OWNED by a Person, the person Should include a Collection of Addresses
class Person
{
<all the stuff you have>
List<Address> Addresses;
}
Don't forget to new it in the constructor,
Then to add an address you just
Address addressInstance = new Address(){...};
PersonInstance.Addresses.Add( addressInstance );
Cal-
If the Person "owns" addresses, it should expose an Addresses property. This could be of type ReadonlyCollection<Address> - no need to create your own collection type.
public Person {
private List<Address> _addresses;
public ReadonlyCollection<Address> Addresses {
get { return _addresses.AsReadOnly(); }
}
public void AddAddress(Address address) {
_addresses.Add(address);
}
}
If you are thinking about good class design, think twice whether every property needs a setter. Maybe you want your object immutable in which case you would want private setters.
That "Save" would follow the "ActiveRecord" pattern. More usual, e.g. when using an ORM like NHibernate, your object crosses some boundary which states that it is stored. In NHibernate this is called a Session which takes care of saving the object according to available information.
Each address should Save(). Your Addresses could Save which would call the save on each of its children.
You'll probably want to have a baseclass which has an enumerable Status such that you'd have New, Modified, UnModified, and Deleted so that you can choose which part of your CRUD will be called. Some people split it up so you'd have booleans, isNew, isModified, isDeleted.
This depends on your architecture...but, for saving the address I would not use the Address object to do it. It's your POCO (Plain old CLR Object) and it shouldn't know about the DAL. Another class should handle CRUD (Creat Read Update Delete) operations and it should be the part of your business layer that interacts with the DAL. Maybe call it AddressComponent.cs? This is a Domain Model Pattern approach.
For the address collection you can just do as flq says and have it as a property...there's really no need to have another object called Addresses.cs unless you need extra logic.
I would use generics to derive List (or any other collection class)
// This class add just an Owner (parent) to the list
public class OwnedList<T> : List<T>
{
public Object Owner { set; get; }
public OwnedList(Object owner)
{
Owner = owner;
}
}
And just pass the the object itself in your class :
class Contact
{
public int Person { get; set; }
private OwnedList<Address> _Addresses;
public OwnedList<Address> Addresses
{
get
{
if (_Addresses == null)
{
_Addresses = new OwnedList<Address>(this);
}
return _Addresses;
}
set
{
_Addresses = value;
_Addresses.Owner = this;
}
}
}
I have a customer hierarchy like so:
abstract class Customer {
public virtual string Name { get; set; }
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
When I retrieve a Customer, I would like to show on the web form the properties to edit/modify. Currently, I use if statements to find the child customer type and show the specialized properties. Is there a design pattern (visitor?) or better way so I can avoid the "if" statements in presentation layer? How do you do it?
Further information: This is an asp.net website with nHibernate backend. Each customer type has its own user control on the page that I would like to load automatically given the customer type.
Can you use reflection to get the list of properties specific to an subclass (instance)? (Less error-prone.)
If not, create a (virtual) method which returns the special properties. (More error prone!)
For an example of the latter:
abstract class Customer {
public virtual string Name { get; set; }
public virtual IDictionary<string, object> GetProperties()
{
var ret = new Dictionary<string, object>();
ret["Name"] = Name;
return ret;
}
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Max spending"] = MaxSpending;
return ret;
}
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Award"] = Award;
return ret;
}
}
You probably want to create sections (fieldsets?) on your Web page, anyway, so if would come into play there, making this extra coding kinda annoying and useless.
I think a cleaner organization would be to have a parallel hierarchy of display controls or formats. Maybe use something like the Abstract Factory Pattern to create both the instance of Customer and of CustomerForm at the same time. Display the returned CustomerForm instance, which would know about the extra properties and how to display and edit them.
new:
interface CustomerEdit
{
void Display();
}
edit:
abstract class Customer {
protected CustomerEdit customerEdit; // customers have an object which allows for edit
public virtual string Name { get; set; }
public void Display() { customerEdit.Display(); } // allow the CustomerEdit implementor to display the UI elements
}
// Set customerEdit in constructor, tie with "this"
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
// Set customerEdit in constructor, tie with "this"
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
usage:
Customer whichCouldItBe = GetSomeCustomer();
whichCouldItBe.Display(); // shows UI depeneding on the concrete type
Have you tried something like this:
public class Customer<T>
where T : Customer<T>
{
private T subClass;
public IDictionary<string, object> GetProperties()
{
return subClass.GetProperties();
}
}
With a subclass of:
public class FinancialCustomer : Customer<FinancialCustomer>
{
}
This is off the top of my head so might not work. I've seen this type of code in CSLA.NET.
Here's the link to the CSLA.NET class called BusinessBase.cs which has a similar definition to what I've given above.