I am tyring to load objects from a SQL server (I am shying away from an orm framework for performance reasons)
My thought was to have a factory class that retreived records from the server and created the appropriate type of objects.
All objects will inherit from an abstract class: aDefinition. Although the concrete objects that derive from aDefintion both share some similar properties, they also have unique properties of their own on top of the base class.
As I am fairly new to programming, I just wanted to get a feel for if I am on the right track.
I couple of questions:
Does it make sense to use an abstract class in this case?
Would it be a good idea to store the collection of definitions in the DefinitionCreator class as a List<aDefinition> and provide it methods for accessing the objects or would it be a better idea to create different concrete collections for the different object types?
public class DefinitionTemplate
{
public int DefinitionId { get; set; }
public string Name { get; set; }
public DefintionType DefinitionType { get; set; }
public string Definition { get; set; }
public string Parameters { get; set; }
public DefinitionTemplate()
{
}
}
//abstract base class that my concrete classes will inherit from.
public abstract class aDefinition
{
public int DefinitionId { get; protected set; }
public string Name { get; protected set; }
public DefintionType DefinitionType { get; protected set; }
//abstract methods
public abstract bool LoadDefinition(DefinitionTemplate template);
public abstract bool SaveDefinition();
}
//concrete class representing a report-type definition.
public class ReportDefinition : aDefinition
{
public string Definition { get; private set; }
public string Parameters { get; private set; }
public override bool LoadDefinition(DefinitionTemplate template)
{
this.DefinitionId = template.DefinitionId;
this.Name = template.Name;
this.DefinitionType = template.DefinitionType;
this.Definition = template.Definition;
this.Parameters = template.Parameters;
return true;
}
public override bool SaveDefinition()
{
throw new NotImplementedException();
}
}
//concrete class representing a configuration-type definition.
public class ConfigDefinition : aDefinition
{
public string Parameters { get; private set; }
public override bool LoadDefinition(DefinitionTemplate template)
{
this.DefinitionId = template.DefinitionId;
this.Name = template.Name;
this.DefinitionType = template.DefinitionType;
this.Parameters = template.Parameters;
return true;
}
public override bool SaveDefinition()
{
throw new NotImplementedException();
}
}
//creator class that retreives the definitions from the server and creates the approprite object
public static class DefinitionCreator
{
public void RetreiveDefinitions()
{
//sql statment to retreive definitions
using(SqlCommand cmd = new SqlCommand("select * from definitions", new SqlConnection()))
{
using(SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
switch (reader["DefinitionType"].ToString())
{
case "ReportDefinition":
//create a report definition object
break;
case "ConfigDefinition":
//create a config definition object
break;
}
}
}
}
}
}
Related
Suppose I have two classes and both contain the same fields
Class A
{
public string Name { get; set; }
public int Designaton { get; set; }
}
Class B
{
public string Name { get; set; }
public int Designation { get; set; }
}
And I have one interface and two classes which are inherited from interface
public interface IDeprt
{
object BindData();
}
And two extractor classes:
public classAItem : IDeprt
{
public object BindData()
{
return new A()
{
// mapping operation
}
}
}
public classBItem : IDeprt
{
public object BindData()
{
return new B()
{
//same mapping operation
}
}
}
My question, how can I implement this in generic way using <T> .
Both classes are doing same operation only return type change. If I am doing in the above way there is lot of duplication of code.
Make your ITem interface and also BindData generic make them use the same generic parameter.
public interface IItem<T>
{
T BindData();
}
Then implement the subclasses like below :
public class AItem : ITem<A>
{
public A BindData(){
return new A(){
// mapping operation
}
}
}
public class BItem : ITem<B>
{
public B BindData(){
return new B(){
//same mapping operation
}
}
}
Edit : As the question evolves.
Make a shared base class for A and B classes.
public abstract class CommonItem
{
public string Name { get; set; }
public int Designaton { get; set; }
}
class A : CommonItem
{
}
class B : CommonItem
{
}
Then make class with a method that accepts a generic parameter with new and CommonItem constraints.
public class Binder
{
public T BindData<T>() where T: CommonItem, new()
{
return new T()
{
// you can access the properties defined in ICommonItem
}
}
}
Usage :
var binder = new Binder();
var boundA = binder.BindData<A>();
var boundB = binder.BindData<B>();
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've inherited a bloated project that uses a huge class as an in-memory database:
public class Database
{
public class Parameter1
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter1Value> paramValues;
}
public class Parameter2
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter2Value> paramValues;
}
public class Parameter1Value
{
public string Value { get; set;}
public Parameter parameter { get; set;}
}
public class Parameter2Value
{
public int Value { get; set;}
public Parameter2 parameter { get; set;}
}
public List<Parameter1> parameter1List { get; set; }
public List<Parameter2> parameter2List { get; set; }
}
I am creating a generic method that creates instances of Parameter1 or Parameter2 (see below) and should add those to their respective lists, but I don't know how to use those types to get the parameter1List or parameter2List instances from my Database class. The Database class holds only one List<T> property for each defined type. Is this possible?
This is the generic method used to create instances:
public static Database Add<T>(this Database database, string code, string label) where T : new()
{
T itemToCreate = (T)Activator.CreateInstance(typeof(T));
itemToCreate.Code = code;
itemToCreate.Label = label;
var listForItem = database.GetList<T>; // This is the missing functionality
listForItem.Add(itemToCreate);
return database;
}
Here is a solution using interfaces and generic constraints.
Create an interface to represent a generic parameter class and add members to the interface as required:
public interface IParameter { ... }
And an interface to represent a list of parameters:
public interface IParameterList<TParameter> where TParameter : IParameter
{
List<TParameter> ParameterList { get; set; }
}
Have the Database and Parameter classes implement these new interfaces:
public class Parameter1 : IParameter
public class Parameter2 : IParameter
public class Database : IParameterList<Parameter1>, IParameterList<Parameter2>
{
List<Parameter1> IParameterList<Parameter1>.ParameterList { get => parameter1List; set => parameter1List = value; }
List<Parameter2> IParameterList<Parameter2>.ParameterList { get => parameter2List; set => parameter2List = value; }
...
}
Add a where TParameter : IParameter constraint to your generic Parameter factory function, and have the factory function require an argument of type IParameterList<TParameter> which is an instance of the Database class. This satisfies the compiler that the Database class owns a list of TParameter. Now we just do db.ParameterList.Add(r) to add our new parameter to the correct list.
public static TParameter CreateParameter<TParameter>(IParameterList<TParameter> db) where TParameter : IParameter, new()
{
var r = new TParameter(); // This is the generic function you mentioned. Do stuff here to create your Parameter class.
db.ParameterList.Add(r); // Add the newly created parameter to the correct list
return r;
}
Code dump (full working version after I picked up your edit which added the generic factory function):
public class Parameter1 : IParameter
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter1Value> paramValues;
}
public class Parameter2 : IParameter
{
public string Code { get; set; }
public string Label { get; set; }
public List<Parameter2Value> paramValues;
}
public class Parameter1Value
{
public string Value { get; set; }
public Parameter parameter { get; set; }
}
public class Parameter2Value
{
public int Value { get; set; }
public Parameter2 parameter { get; set; }
}
public class Database : IParameterList<Parameter1>, IParameterList<Parameter2>
{
// Note: Setters for the List properties probably not needed here or in IParameterList as with the following code we instantiate them at class construction time and, in this MCVE at least, there are no further assignments
public List<Parameter1> parameter1List { get; set; } = new List<Parameter1>();
public List<Parameter2> parameter2List { get; set; } = new List<Parameter2>();
List<Parameter1> IParameterList<Parameter1>.ParameterList { get => parameter1List; set => parameter1List = value; }
List<Parameter2> IParameterList<Parameter2>.ParameterList { get => parameter2List; set => parameter2List = value; }
public static TParameter Add<TParameter>(IParameterList<TParameter> db, string code, string label) where TParameter : IParameter, new()
{
var itemToCreate = new TParameter();
itemToCreate.Code = code;
itemToCreate.Label = label;
db.ParameterList.Add(itemToCreate); // Add the newly created parameter to the correct list
return itemToCreate;
}
}
public interface IParameter
{
string Code { get; set; }
string Label { get; set; }
}
public interface IParameterList<TParameter> where TParameter : IParameter
{
List<TParameter> ParameterList { get; set; }
}
// Testing:
void Main()
{
var db = new Database();
Database.Add<Parameter1>(db, "hello", "hello2");
Database.Add<Parameter1>(db, "hello", "hello2");
Database.Add<Parameter2>(db, "hello", "hello2");
Console.WriteLine($"P1 count (should be 2): {db.parameter1List.Count()}; P2 count (should be 1): {db.parameter2List.Count}");
}
Output:
P1 count (should be 2): 2; P2 count (should be 1): 1
Here is a solution which acquires the target list using generics and reflection:
public static List<T> GetList<T>(this Database dataBase) where T : new()
{
return dataBase.GetType()
.GetProperties()
.Where(x => x.PropertyType == typeof(List<T>))
.Select(x => (List<T>)x.GetValue(dataBase))
.FirstOrDefault();
}
Credit: Michael Randall in the comments
I have an abstract class "RiskBaseCollection" that uses generics to essentially be a container for a dictionary. The type of items stored in this dictionary must be passed in the constructor, and they must inherit from a base class called "RiskBase":
I have a method in the dictionary container class that calls a database query to populate the contents of the dictionary (the database call depends on what is set within another field, but that's not important to my point).
When populating the dictionary, for each database record, I want to see whether an appropriate instance of a class has already been created and stored: If it has, I retrieve it and add additional values to it. If it hasn't, I create a new instance of the RiskBase class. I have done this with Generics, such that the correct type of RiskBase is actually created.
What I am struggling with, is that I want to tell each instance of the "RiskBase" class what collection 'owns' it. I've tried various means, but can't get it to work.
Here is an extract of the Collection class, and the entire RiskBase class:
public abstract class RiskBaseCollection<T> where T : RiskBase, new()
{
public Dictionary<int, T> Items = new Dictionary<int, T>();
#region Non-critical stuff
//Removed - not important to my issue.
#endregion
public void ReadData()
{
if (ValidConnectionInfo == false)
{
return;
}
//Create the connection:
using (OleDbConnection conn = new OleDbConnection(ReaderConnectionString))
{
if (conn != null) conn.Open();
if (conn.State == System.Data.ConnectionState.Open)
{
using (OleDbCommand command = new OleDbCommand(SQL, conn))
{
if (command != null)
{
using (OleDbDataReader reader = command.ExecuteReader())
{
if (reader != null && reader.HasRows)
{
while (reader.Read())
{
int RiskID = reader.GetValue<int>("ID");
string Title = reader.GetValue<string>("TITLE");
string Status = reader.GetValue<string>("STATUS");
DateTime RaisedDate = reader.GetValue<DateTime>("RAISED_DATE");
DateTime ExpiryDate = reader.GetValue<DateTime>("EXPIRY_DATE");
//Get the FLOC string for the current record
string FunctionalLocation = reader.GetValue<string>("FUNCTIONAL_LOCATION");
T thisRisk = (Items.ContainsKey(RiskID)) ? (T)Items[RiskID] : new T();
thisRisk.RiskID = RiskID;
thisRisk.Title = Title;
thisRisk.Status = Status;
thisRisk.RaisedDate = RaisedDate;
thisRisk.ExpiryDate = ExpiryDate;
thisRisk.AddFunctionalLocation(FunctionalLocation);
thisRisk.Owner = this; //<=Error: Cannot implicitly convert type 'CRT.Risks.RiskBaseCollection<T>' to 'CRT.Risks.RiskBaseCollection<CRT.Risks.RiskBase>'
Items[RiskID] = thisRisk;
}
}
}
}
}
}
}
}
}
public class RiskBase
{
public RiskBaseCollection<RiskBase> Owner { get; set; }
public virtual RiskType RiskType { get; set; }
public RiskBase() { }
public RiskBase(RiskBaseCollection<RiskBase> riskBaseCollection, RiskType riskType)
{
Owner = riskBaseCollection;
RiskType = riskType;
}
public virtual int RiskID { get; set; }
public virtual string Title { get; set; }
public virtual string Status { get; set; }
public virtual DateTime RaisedDate { get; set; }
public virtual DateTime ExpiryDate { get; set; }
public virtual List<string> FunctionalLocations { get; set; } = new List<string>();
public virtual void AddFunctionalLocation(string functionalLocation)
{
if (!FunctionalLocations.Contains(functionalLocation)) FunctionalLocations.Add(functionalLocation);
}
}
Essentially, I'm after a means of setting the "Owner" Property for the RiskBase class.
Make RiskBaseCollection<T> implement a covariant generic interface, and change the RiskBase.Owner property's type to this interface:
// new interface
interface IRiskBaseCollection<out T>
{
// interface members
}
public abstract class RiskBaseCollection<T> : IRiskBaseCollection<T>
where T : RiskBase, new()
{
// ...
thisRisk.Owner = this; // this now compiles!
}
public class RiskBase
{
public IRiskBaseCollection<RiskBase> Owner { get; set; } // interface reference
// ...
}
I am trying to make my method generic and I am stuck at a point and need your assistance. The code scenario is I have an abstract class say MyBaseAbs which contains common properties:
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
}
Now I have child classes:
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
}
and another child class:
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
}
Now I have to create a common method which needs to perform some operations on the basis of Mychild1 and Mychild2, so what I did is:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
}
so inside this method I need to write common code which does the mapping for SaveObject object according to the child object passed. How can I determine which object is passed and use properties accordingly.
One option would be to create a base Save function in your base class and make it virtual.
Then override the method in your child classes. This way when you call the Save method in your SaveOperation it should call the appropriate method from the correct child class.
public abstract class MyBaseAbs
{
public string CommonProp1 { get; set; }
public string CommonProp2 { get; set; }
public string CommonProp3 { get; set; }
public virtual void Save() { }
}
public class Mychild1: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild1Prop2 { get; set; }
public string Mychild1Prop3 { get; set; }
public override void Save() {
//Implementation for Mychild1
}
}
public class Mychild2: MyBaseAbs
{
public string Mychild1Prop1 { get; set; }
public string Mychild2Prop2 { get; set; }
public override void Save() {
//Implementation for Mychild2
}
}
If you can't modify your business objects, you can check the type of the concrete class in the SaveOperation method:
public MyCustomClass SaveOperation<T>(T myObj)
where T : MyBaseAbs
{
SaveObject obj = new SaveObject();
if (myObj is Mychild1) {
Mychild1 mychild1 = (Mychild1) myObj;
// Business logic for object of type Mychild1
} else if (myObje is Mychild2) {
Mychild2 mychild2 = (Mychild2) myObj;
// Business logic for object of type Mychild2
}
}
Notice that this is not a very solid solution as, if you are creating new objects that implement your abstract class, you will have to remeber to add another branch in the if statement.
As #BojanB mentioned, the obvious solution would be to create a virtual method in your base class and override it in the derived, but if you cannot modify the code there then you can create a method for each derived class and create a dictionary that maps each type to its method:
private Dictionary<Type, Action<MyBaseAbs, MyCustomClass>> _saveOperations =
new Dictionary<Type, Action<MyBaseAbs, MyCustomClass>>();
//You can then set an entry for each of your derived classes
_saveOperations[typeof(Mychild1)] = (myObj, myCustomObj) =>
{
//Mychild1-specific logic
};
public MyCustomClass SaveOperation(MyBaseAbs obj)
{
//do the common saving operations here
var result = new MyCustomClass();
//....
var actualType = obj.GetType();
if(_saveOperations.ContainsKey(actualType))
{
_saveOperations[actualType](obj, result);
}
return result;
}
You can then add an item to the dictionary for each derived class. It is the same concept as using the is operator but allows you to add methods for more derived types without modifying the original SaveOperation method
You can use C#'s As-Operator as follows:
Mychild1 child1 = myObj as Mychild1;
if(child1 != null) {
//Here you can use child1.Mychild1Prop1 forexample
}
Link to msdn: https://msdn.microsoft.com/en-us/library/cscsdfbt.aspx