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;
}
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 been trying to find an elegant way to avoid repeating code in all of my derived classes. At this point, I am unsure as to the best way to proceed.
I'd like to write a single method in the base class that will instantiate and use any of its derived classes without having to edit the method when I write new derived classes.
I have tried learning/using a generic method but started to think I might be heading down a dead end for this application. I understand that using reflection can be expensive, and since this method is meant to handle hundreds or even thousands of Elements, it seemed like a bad idea.
Now I'm thinking of trying to pass in the class itself as an argument somehow... maybe. That doesn't seem quite right to me either.
I'm willing to do the research, but would love any help pointing me in the right direction.
Here is an abridged version of what I have...
Base Class:
public abstract class Element
{
public string ElementName { get; }
public List<string> BadParameters { get; set; } = new List<string>();
//Constructor
public Element(string name)
{
ElementName = name;
}
//The method in question---
public static List<string> GetBadParameters(//derived class to instantiate)
{
var elem = new //derived class();
return elem.BadParameters;
}
}
Derived Class 1:
public class Wall : Element
{
public double Length { get; set; }
public bool LoadBearing { get; set; }
//Constructor
public Wall(string name): base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = //A wall specific way of setting bad parameters
}
}
Derived Class 2:
public class Floor : Element
{
public double Area { get; set; }
public double Slope { get; set; }
//Constructor
public Floor(string name): base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = //A floor specific way of setting bad parameters
}
}
Implementation:
public class Implementation
{
public List<string> GetAllBadElementParameters()
{
List<string> output = new List<string>;
List<string> badWalls = GetBadParameters(//Wall class)
List<string> badFloors = GetBadParameters(//Floor class)
output = output.AddRange(badWalls).AddRange(badFloors);
return output;
}
}
EDIT - To clarify:
The actual content of
public List<string> BadParameters
does not matter. Bad parameters, how and why they are bad, are inconsequential.
What I'm trying to accomplish is avoid having the method "GetBadParameters()" defined in the derived class, since this method will be the exact same for all derived classes.
It is only the populating of the "BadParameter" base class property that changes from one derived class to another.
EDIT 2 - My attempt at a generic method in the base class:
I know this won't work, but it may convey what I'd like to have happen.
public static List<string> GetAllBadParameters<T>(List<string> names) where T : ANY DERIVED CLASS, new()
{
List<string> output = new List<string>();
foreach (string name in names)
{
var elem = new T(name);
foreach (string badParameter in elem.BadParameters)
{
output.Add(badParameter);
}
}
return output;
}
Well … First of all, I am guessing that by "bad parameter" you mean the name of a property in an Element-derived class. For example I'm guessing that if the Length of a Wall is negative then "Length" would be a bad parameter of that particular Wall. Secondly I'm guessing that you are going to have a largish number of elements, e.g. a number of walls and floors (and other things) in a diagram or whatever.
Assuming that, then one way to do this would be to have an abstract method in the Element class that returns the bad parameters, and implement it in each derived class. Something like this:
public abstract class Element
{
public string Name { get; private set; }
public abstract IList<string> GetBadParameters();
public Element( string name) { this.Name = name; }
}
public class Wall
{
public Wall( string name): base(name) {}
public double Length { get; set; }
public bool IsLoadBearing { get; set; }
public IList<string> GetBadParameters() {
List<string> bad = new List<string>();
if (this.Length <= 0) { bad.Add( this.Name + ": " + nameof( this.Length); }
if (this.IsLoadBearing && this.Length > whatever) { bad.Add( this.Name + ": " + nameof( this.IsLoadBearing); }
return bad;
}
}
Then if you had a list of all the elements you could get all the bad parameters by
IList<string> allBadParemeters = elements.SelectMany( e => e.GetBadParameters() );
What I would say though is that this might not be such a great design. You would end up with a system in which a lot of elements contain bad parameters. Life could be a lot easier if you just prevent bad parameters from happening in the first place. You can do this by making the 'set' methods of all the parameter properties private and adding a method such as bool Wall.TrySetParameters( double length, bool isLoadBearing). If the parameters are bad then this would just return false and not assign the parameters to the wall. If you want to have TrySetParameters in the base class then you could do it with a more general signature such as
public struct Parameter {
public Parameter( string name, object value) { … }
public string Name { get; private set; }
public object Value { get; private set; }
}
abstract public class Element {
…
abstract public bool TrySetParameters( params Parameter[] parameters);
}
I am assuming your BadParameter list content is same for all derived Classes. If this list is not common then there is no point in filling these list in Base Class.
By that assumption I can suggest you following changes .
Your base class looks like this . There is no need of making GetBadParameters() as static
public abstract class Element
{
public string ElementName { get; }
public List<string> BadParameters { get; set; } = new List<string>();
//Constructor
public Element(string name)
{
ElementName = name;
}
/// <summary>
/// Tjis Method is common for alal derived classes. Assuming content is same for all dervied class
/// </summary>
/// <returns></returns>
//The method in question---
public List<string> GetBadParameters()
{
return new List<string>() { "1", "2" };
}
}
Your first derived class Wall, where it will call GetBadParameters from base .
public class Wall : Element
{
public double Length { get; set; }
public bool LoadBearing { get; set; }
//Constructor
public Wall(string name) : base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = GetBadParameters();//Calling base GetBadParameters
}
}
Same goes with second derived class "Floor"
public class Floor : Element
{
public double Area { get; set; }
public double Slope { get; set; }
//Constructor
public Floor(string name) : base(name)
{
SetBadParameters();
}
public void SetBadParameters()
{
BadParameters = GetBadParameters();//Calling base GetBadParameters
}
}
In your implementation class, you can create both wall and floor objects by keeping Element class as reference and call respective GetBadParameters
public class Implementation
{
public List<string> GetAllBadElements()
{
List<string> output = new List<string>;
Element _wall = new Wall("wall");
Element _floor = new Floor("floor");
List<string> badWalls = _wall.GetBadParameters(); //Returns Wall bad Parameters
List<string> badFloors = _floor.GetBadParameters(); //Returns Floor bad Parameters
output = output.AddRange(badWalls).AddRange(badFloors);
return output;
}
}
I have a class like this
public class OwnerWithholding
{
private decimal ManagementFeePct;
private decimal TotalManagementFee;
private decimal OperationalFeesPct;
private decimal TotalOperationalFees;
}
And I have calculation method that create object of this class, fill it with some arithmetic operations, and return this object.
public OwnerWithholding CalculationMethod1(Reservation r, SqlConnection conn)
{
OwnerWithholding result = new OwnerWithholding();
// result.ManagementFeePct = some data from Fees table in DB + value
//from another db - constant value..
// Also with other properties - with some operations on data
//result.TotalManagementFee = ..
// result.OperationalFeesPct = ..
// result. TotalOperationalFees = ..
return result;
}
And now it works fine.
But this calculation method is just one option for populating data.
There is another calculation method, implemented in a completely different way, but filling exactly the same properties of the object. And I may have more of them.
I need a pattern that would allow me to create objects of the same class, just indicating the calculation method that is needed.
I like the strategy pattern , where the algorithms will be the methods that fill the objects that called them.
But it doesn’t look very good.
Maybe a factory method would be more appropriate here, but I don’t know how to implement it.
Edit: Going by the OPs comments now, it looks like just ONE method in the class needs to be set in multiple ways.
The Template pattern (or the Builder) are better fits in this case, not the Factory.
Template Pattern.
a. Abstract Base class that set default properties, but leaves out one property (Get Ingredients) to be populated by the concrete classes.
public abstract class PizzaCreator
{
public abstract string GetIngredients { get; }
public string Bake { get; set; } = "Bake at 400F for 30 minutes";
public string Deliver { get; set; } = "Deliver in custom box";
}
b. Two Pizza classes, for now just overriding the abstract property
public class CheesePizza : PizzaCreator
{
public override string GetIngredients
{
get { return GetMyIngredients(); }
}
string GetMyIngredients()
{
return "Lots of Cheese!";
}
}
public class PepperoniPizza : PizzaCreator
{
public override string GetIngredients
{
get { return GetMyIngredients(); }
}
string GetMyIngredients()
{
return "Lots of Meats!";
}
}
Here I'm creating instances of the Pizza
var pepPizza = new PepperoniPizza();
var chessePizza = new CheesePizza();
You could even have these creations routed through a Factory class/method.
Original answer:
Here is the Abstract Factory Pattern.
This code goes into the Factory class library.
a.ICar interface
public interface ICar
{
string Name { get; set; }
int Doors { get; set; }
string EngineCapacity { get; set; }
}
b.Abstract Car Factory
public abstract class AbstractCarFactory
{
public abstract ICar CreateCar(CarType type);
}
c.Two Concrete Cars -
internal class NissanPickUpTruck : ICar
{
public string Name { get; set; }
public int Doors { get; set ; }
public string EngineCapacity { get ; set ; }
}
internal class NissanSportsCar: ICar
{
public string Name { get; set; }
public int Doors { get; set; }
public string EngineCapacity { get; set; }
}
d.Concrete Factory
public class NissanFactory : AbstractCarFactory
{
public override ICar CreateCar(CarType type)
{
switch (type)
{
case CarType.PickupTruck:
return new NissanPickUpTruck{Name = "Titan", Doors = 6, EngineCapacity = "V12"};
case CarType.SportsCar:
return new NissanSportsCar{Name = "350Z", Doors = 2, EngineCapacity = "V6"};
default:
throw new Exception();
}
}
}
Finally the calls from an external project
var nissanFactory = new NissanFactory();
var sportsCar = nissanFactory.CreateCar(CarType.SportsCar);
var pickUpTruck = nissanFactory.CreateCar(CarType.PickupTruck);
But like the other comment, the Builder is something worth checking out as well.
I have an interface for items which are Votable: (Like StackExchange, Reddit, etc...)
// Irrelevant properties left out (Creator, Upvotes, Downvotes, etc)
internal interface IVotable
{
double HotScore { get; set; }
double VoteTotal { get; set; }
DateTime CreatedDate { get; set; }
}
I have a concrete base class which extends this interface and defines a constructor to populate the default properties:
internal class SCO : IVotable
{
public double HotScore { get; set; }
public double VoteTotal { get; set; }
public DateTime CreatedDate { get; set; }
public SCO(SPListItem item, List<Vote> votes)
{
VoteTotal = UpVotes - DownVotes;
HotScore = Calculation.HotScore(Convert.ToInt32(UpVotes), Convert.ToInt32(DownVotes), Convert.ToDateTime(item["Created"]));
CreatedDate = Convert.ToDateTime(item["Created"]);
}
Here is an example of a class in use which extends this base class and it's constructor:
class Post : SCO
{
public string Summary { get; set; }
public Uri Link { get; set; }
public Post(SPListItem item, List<Vote> votes)
: base(item, votes)
{
Summary = (string) item["Summary"];
Link = new UriBuilder((string) item["Link"]).Uri;
}
}
Over 90% of the time, I'm returning sorted collections of the classes for rendering on a page.
I would like to have a generic method of some kind that takes in a collection of DataBase Items, a List of Votes to match with the Items, creates a List, and then sorts that list based on a passed ENUM that defines how to sort.
I've tried a few approaches, many of them based on previous posts. I'm not sure if I'm approaching this in the right way. While the solutions do work, I see a lot of Boxing, or Reflection, or some kind of (possibly major) sacrifice in performance for readability, or ease of use.
What is the best way to Create a Sorted List of objects that can be used in any subsequent child class as long as that class extends the base class?
Previous Approach that is working:
Create a List of <T> from a base class
A Generic List of <T> embedded in the Base Class which extends Activator.CreateInstance using reflection to return the list:
public static List<T> SortedCollection<T>(SPListItemCollection items, ListSortType sortType, List<Vote> votes) where T : SCO
Request for Sample of use:
static public List<Post> Get100MostRecentPosts(ListSortType sortType)
{
var targetList = CoreLists.SystemAccount.Posts();
var query = new SPQuery
{
Query = "<OrderBy><FieldRef Name=\"Created\" Ascending=\"False\" /></OrderBy>",
RowLimit = 100
};
var listItems = targetList.GetItems(query);
var votes = GetVotesForPosts(listItems);
return Post.SortedCollection<Post>(listItems, sortType, votes);
}
I have this C# class structure that I would like to refactor to use best coding standards (use interfaces/abstract classes) so it can be more maintainable and reusable. The code as it is right now isn't awful, but it's not ideal.
I have a series of TableItemGroup classes: AccountTableItemGroup, PendingVoteTableItemGroup, and RequestingVoteTableItemGroup. Each TableItemGrup contains a string SectionName and a List for its corresponding TableItem ...as such:
public class AccountTableItemGroup {
public string SectionName { get; set; }
public List<AccountTableItem> Items
{
get { return this._items; }
set { this._items = value; }
}
public List<AccountTableItem> _items = new List<AccountTableItem>();
public AccountTableItemGroup()
{
}
}
In the future there will be many more TableItemGroups and if they are all the same except for the List part, I don't want to have to copy the code and create a new Group every time and make that small change. I know there must be a better way. I would like to keep using the List<> generics so I don't have to cast anything later though.
The other part are the TableItems. I have AccountTableItem, PendingVoteTableItem, and RequestingVoteTableItem. The TableItems are different from each other, but they each share three common strings -- TitleLabel, DetailLabel, and ImageName. But after that, each TableItem may or may not have additional properties or methods along with it ..as such:
public class AccountTableItem
{
public string TitleLabel { get; set; }
public string DetailLabel { get; set; }
public string ImageName { get; set; }
public bool SwitchSetting { get; set; }
public AccountTableItem()
{
}
}
So my question to all of you is, how do I redefine my class structure to allow for as much reuse of code as possible and to use best coding standards?
I was thinking of having an abstract TableItem class or use an interface for the TableItemGroup? I know that using an interface or an abstract class is best for coding standards, but I don't see how it would cut down on the amount of code I will have?
Thanks a lot for any help.
Abstract away your table item adding necessary fields to the interface or base class:
interface ITableItem // or just a simple or abstract class
{
// common fields go here
}
Then can you make your item group generic with a constraint on generic parameter.
public class ItemGroup<T> where T: ITableItem
{
public string SectionName { get; set; }
public List<T> Items { get; private set; }
public ItemGroup()
{
Items = new List<T>();
}
}
Consider using generics to represent the TableItemGroup container, and make a base class for your TableItem, which you can inherit from for specific types of table item. If you inherit directly from List<T>, then you can treat your item group as a collection without having to use the Items property as in your existing design.
There's not much point in using interfaces for these sorts of types. As they stand they are data classes so have no behavior. If they had behavior, using interfaces would make sense as you would then be able to change implementations and so vary behavior.
public class TableItemGroup<T> : List<T> where T : TableItem
{
public TableItemGroup(string sectionName)
{
SectionName = sectionName;
}
public string SectionName { get; private set; }
}
public class TableItem
{
public string TitleLabel { get; set; }
public string DetailLabel { get; set; }
public string ImageName { get; set; }
}
public class AccountTableItem : TableItem
{
public bool SwitchSetting { get; set; }
}
Now that we have a generic TableItemGroup container, you can re-use this for all TableItem types. Having a base class for TableItem again gives you some re-use.
var items = new TableItemGroup<AccountTableItem>("Accounts");
items.Add(new AccountTableItem { SwitchSetting = true });
Unless you want users to be able to add and remove new lists at will, you should make the setter on the items list protected. Users will still be able to add and remove items, but not create a reference to a new list.