In an abstract class (C# 3), there is a virtual method named GetData which returns a DataTable. The algorithm of the method is as following:
Get SQL query string from the class.
Get DataTable from database using above query.
Do transformations on DataTable and return it.
In the 3rd point, I clone the original DataTable in order to change the Type of column (I can't do that on populated table and can't setup this at the 2nd point) and enumerate every row in which I copy and transform data from the original one. Transformations depends on the class, every one has private methods which transforms data on its own.
The question is: How to make a method in a base class which will be based on the following three params: column name which will be converted, Type of new column and action during the transformation. Two first are quite simple but I'm not sure about the third one. I thought about designing a new class which will store these three parameters, and the action will be stored as following delegate:
public delegate object Convert(object objectToConvert);
The conversion would look something like that:
int rowCounter = 0;
foreach(DataRow row in dt.Rows)
{
foreach(var item in Params)
{
row[item.ColumnIndex] = item.Convert(originalDataTable.Rows[rowCounter].ItemArray[item.ColumnIndex]);
}
++rowCounter;
}
For now, I have to override the method GetData() in every class I want to have a transformations which causes a large duplication of code. The point I want to achieve is to make a base class which will be based on params I mentioned above. Is the above solution good for this problem or is it any other way to do that?
First I'm not a big fan of DataTable, you can use DataReader instead if you do a foreach.
using (var dataReader = ....)
{
while(dataReader.Read())
{
foreach(var item in Params)
{
row[item.ColumnIndex] = item.Convert(originalDataTable.Rows[rowCounter].ItemArray[item.ColumnIndex]);
}
}
}
Second, make a base class with a abstract method with some code and make the object in the list Params inherits of this class and override the method only when it necessary.
public class MyClass
{
public abstract object Convert(DataRow row)
{
....
}
}
public class foo : MyClass
{
}
Okay, for now I have a following solution which does fully satisfy me:
Every convertor implements following interface:
public interface IConvertor
{
object Convert(object item);
}
Params class is as following:
Type ColumnType { get; protected set; } // New type
string[] ColumnNames { get; protected set; }
IConvertor Convertor { get; protected set; }
Every object have its own Params array property. I've got one method for every derived class and all what I have to do is to set up parameters.
Related
I want to access the field names of an object which ist nested into a structure as follows:
public class Playerframe
{
public string Attr1;
public string Attr2;
}
public class MatchMoment
{
public int MomentNr;
public Dictionary <int, Playerframe> PlayerData;
}
public DataTable CreateTable (List<dynamic>Moments)
{
DataTable table = new DataTable();
List<string> = Moments[0]......
/// get all class Properties, including the Playerframe properties in order
/// to create correctly named DataTable columns
/// The List<string> should finally contain {"MomentNr","Attr1","Attr2"}
return table;
}
My question now would be how to access the field names("e.g. Attr1") stored in the Dictionary value within a MatchMoment object object using System.Reflection?
I want to write a function which creates a datatable object out of the properties of any given object which is defined in the method parameter, as shown above.
Thx for your help!
Max
I think the following snippet might get you what you want. Basically, it iterates over the properties of the element type of the list to get their names, and in case of a generic property type, recursively gets the names of the properties of the generic type arguments.
public DataTable CreateTable(List<dynamic> Moments)
{
var table = new DataTable();
var elementType = GetElementType(Moments);
var propertyNames = GetPropertyNames(elementType);
// Do something with the property names . . .
return table;
}
private static Type GetElementType(IEnumerable<dynamic> list) =>
list.GetType().GetGenericArguments()[0];
private static IEnumerable<string> GetPropertyNames(Type t)
{
return t.GetProperties().SelectMany(getPropertyNamesRecursively);
IEnumerable<string> getPropertyNamesRecursively(PropertyInfo p) =>
p.PropertyType.IsGenericType
? p.PropertyType.GetGenericArguments().SelectMany(GetPropertyNames)
: new[] { p.Name };
}
Note that this only looks at properties, and your current classes exclusively use fields. However, the use of properties is considered best practice for public access to data, so it might be worthwhile to change your fields to properties. If you really want to keep them as fields, you might have to tweak it a bit, but the idea of recursively unfolding generic types remains the same.
Here is what I am looking at doing. Say I have a Class with a number of properties. I am trying to write a method that looks something like this
public static void GetNullableInt32(this DbDataReader reader, Type property)
{
property = reader.IsDBNull(reader.GetOrdinal(property.name))
? (int?)null
: reader.GetInt32(reader.GetOrdinal(property.name));
}
Where the property name is pulled from reflection, and the property is set in the method. I put in Type in the parameters as a placeholder for whatever type it needs to be. Then I would call it like
reader.GetNullableInt32(Class.Property1);
To set all the properties on a class from a database reader.
Is there an easy way to do this? Or is there a better structure where instead of having to enter the column name as a string it is pulled from the column name?
Edit
In response to a deleted comment asking why we don't just pass in the string name, the code used to look something like
Class item = new Class {
ContactRelationId = reader.IsDBNull(reader.GetOrdinal("ContactRelationId"))
? (int?)null
: reader.GetInt32(reader.GetOrdinal("ContactRelationId"))}
And the requirement passed down was that we should not store package procedures as strings.
you would need to send through the instance of the object that has the property, that is going to get that property set on it. if your class looked like:
public class MyClass
{
public int? MyInt { get; set; }
}
you'd have to send an instance to this method:
public static void GetNullableInt32(this DbDataReader reader, MyClass instance, string propName)
But why use reflection when you don't have to? It's slower, can often lead to bugs. Just do the assignment in the calling method:
public static void GetNullableInt32(this DbDataReader reader, string propName)
{
//...
}
//calling method
myClassInstance.MyInt = reader.GetNullableInt32(nameof(MyClass.MyInt));
all this assumes that your column names and property names are identical, as you seem to have specified they are.
I have data from multiple organisations (police, fire, office) that need output in different formats.
To achieve this, I defined the following (this is a little simplified):
Transaction class -
"Success" indicator - Boolean.
"Type of department"- String or Enum.
A class which can be of any type - Police, Fire or Office (My question is on this as you will see).
A GenerateOutput() method - to handle generation of file formats.
Police class
Age - String
VehicleNumber - Integer
Supervisor - String
Fire class
Name - String
FireEngineNumber - Integer
County - Enum
WorkTimings - Enum
Office Class
Age - String
DeskNumber - Integer
Department - String
PayScale - Enum
IsManagement - Bool
As you can see, the Police, Fire and Office classes dont share anything in common and are primarily intended as data carrying entities. I intend to use a Factory to return an appropriate generic (not a C# generic) Transaction object with the data (Transaction object with Police, Fire or Office data within it) and then pass the returned object to a Strategy pattern which determines the file format (CSV, Excel, or XML; specified in a configuration file) each one needs.
My problem is in the definition of the Transaction object.
What type does the class in "3." of the Transaction class need to be? The data for each org differs, there are no common members, I am unable to define a common class for all.
Is the overall design appropriate? What other designs should I consider?
Based on Peter's comments below:
I think using generics might work, I ran into a problem though. I would like to use a factory to return the object requested, using GetTransactionObject, as below. What should be the return type of GetTransactionObject to accomodate this.
class TransactionFactory
{
Dictionary<string, Type> typeClassLookup;
public TransactionFactory()
{
typeClassLookup = new Dictionary<string, Type>();
typeClassLookup.Add("Police", typeof(PoliceData));
typeClassLookup.Add("Fire", typeof(FireData));
}
Transaction<????> GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
If the types really have nothing in common, then you need no explicit base class. System.Object suffices, just as with many other generic types (i.e. any generic type lacking a constraint).
In other words, you could declare as:
class Transaction<T>
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { /* something goes here */ }
}
Personally, I would avoid adding a "department type" member. After all, that's implicit from the type parameter T. But you could add that easily to the above if you want.
If and when you find that the types do have something in common, such that your Transaction<T> type needs to do more than simply hold onto an instance of one of those types (which is about all it can do without a constraint), then you will be able to put that commonality into an interface or base class (depending on the specific need), and specify that in a constraint for the Transaction<T> class.
Note that it's not clear what you mean for the GenerateOutput() to do, or how it should work. But assuming that you want output that is specific for each Entity value, it seems to me that that is your "something in common". I.e., it's not the Transaction<T> class at all that needs to implement that method, but rather each entity type. In that case, you have something like this:
interface IDepartmentEntity
{
void GenerateOutput();
}
class Office : IDepartmentEntity
{
public void GenerateOutput() { /* department-specific logic here */ }
}
// etc.
Then you can declare:
class Transaction<T> where T : IDepartmentEntity
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { Entity.GenerateOutput(); }
}
EDIT:
Per Prasant's follow-up edit, with a request for advice on the GetTransactionObject()…
The right way to do this depends on the caller and the context, a detail not provided in the question. IMHO, the best scenario is where the caller is aware of the type. This allows the full power of generics to be used.
For example:
class TransactionFactory
{
public Transaction<T> GetTransactionObject<T>()
where T : IDepartmentEntity, new()
{
return new Transaction<T>()
{
Data = new T(),
params = null
}
}
}
Then you call like this:
Transaction<FireData> transaction = factory.GetTransactionObject<FireData>();
The caller, of course already knowing the type it is creating, then can fill in the appropriate properties of the transaction.Data object.
If that approach is not possible, then you will need for Transaction<T> itself to have a base class, or implement an interface. Note that in my original example, the IDepartmentEntity interface has only one method, and it's the same as the GenerateOutput() method in the Transaction class.
So maybe, that interface is really about generating output instead of being a data entity. Call it, instead of IDepartmentEntity, something like IOutputGenerator.
In that case, you might have something like this:
class Transaction<T> : IOutputGenerator
{
// all as before
}
class TransactionFactory
{
public IOutputGenerator GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
}
}
This is an inferior solution, as it means the caller can only directly access the IOutputGenerator functionality. Anything else requires doing some type-checking and special-case code, something that really ought to be avoided whenever possible.
Note: if the Transaction type has other members which, like the GenerateOutput() method, are independent of the contained type T here, and which would be useful to callers who don't know T, then a possible variation of the above is to not reuse the interface used for the department-specific data types, but instead declare a base class for Transaction<T>, named of course Transaction, containing all those members not related to T. Then the return value can be Transaction.
What type does the class in "3." of the Transaction class need to be?
To decouple your department classes from the various export types, I recommend you make the department classes implement a common interface. Something like this:
public interface Exportable {
// return a list of attribute names, values, and types to export
IList<Tuple<String, String, Type>> GetAttributes();
}
For example:
public class Police : Exportable {
public IList<Tuple<String, String, Type>> GetAttributes() {
// return list size 3 - attribute info for Age, VehicleNumber, Supervisor
}
}
Is the overall design appropriate? What other designs should I consider?
The Transaction class design doesn't seem well suited for this problem.
Consider an Export class with a method for each export type, each method which receives the attributes returned from the Exportable interface method. Basic outline:
public static class Export {
public static boolean CSV(IList<Tuple<String, String, Type>> attributes) {
// export attributes to CSV, return whether succeeded
}
public static boolean Excel(IList<Tuple<String, String, Type>> attributes) {
// export attributes to Excel, return whether succeeded
}
// same thing for XML
}
I am trying to bind some controls to an object - which is normally a pretty straightforward process. Unfortunately, if the object that I'm binding to inherits from CollectionBase, binding to that classes fields causes the error:
Cannot bind to the property or column Caption on the DataSource. Parameter name: dataMember
Removing the collectionbase inheiritance makes this issue go away, but I need this object to be a collection. It seems as though CollectionBase causes higher level properties to become "unbindable." Is there some property I can override to fix this? Any other ideas?
I found this example online that summarized the issue pretty easily. Unfortunately, I have yet to find an answer in all the places I've seen this example posted.
Code:
[STAThread]
static void Main()
{
TestCollection obj = new TestCollection();
using (Form f = new Form())
using (BindingSource bs = new BindingSource())
{
bs.DataSource = typeof(Test);
f.DataBindings.Add("Text", bs, "Caption");
bs.DataSource = obj; // breaks
//List<TestallData = new List<Test>();
//allData.Add(obj);
//bs.DataSource = allData;
f.ShowDialog();
}
}
class TestCollection : CollectionBase
{
public string Caption { get { return "Working"; } }
}
CollectionBase provides interfaces for a List of Objects, as such when used as a datasource the binding tries to look inside the list for the individual binding data. When there is no list, you have a problem.
If you want a the caption and you want to use CollectionBase you should have 2 classes involved, not just one.
public class TestObj
{
public string caption { get { return "yay"; } }
}
public class TestCol : CollectionBase
{
//methods that implement CollectionBase for the TestObj type
}
with those two you can bind one of two ways.
TestObj obj = new TestObj();
TestCol col = new TestCol();
col.Add(obj);
//bind to obj, OR bind to col. Both would work with this setup.
http://msdn.microsoft.com/en-us/library/system.collections.collectionbase%28v=vs.90%29.aspx
There is a sample implementation of CollectionBase there.
UPDATE: EDITED FROM COMMENT
There isn't any method that I personally know which allows you to bind to the outer properties of a collection. As a workaround, you can use a 3 class system (yea, I know, more and more complicated).
public class TestHeader
{
public string Data {get;set;}
}
public class TestCol : CollectionBase
{
//...
}
public class TestObj
{
public TestHeader header {get;set;}
public TestCol col {get;set;}
}
bind the outer fields to TestObj.header and bind the collection fields to TestObj.col. This is a workaround, but as stated I dont actually know a way to directly implement what you seem to want. I wish I did, There are portions of my own code that would benefit from it.
Another Example
You could also do it with two classes, but you would still need to nest the collection itself
public class TestObj
{
public string data {get;set;}
public TestCol col {get;set;}
}
In this case, bind single data fields to TestObj, and collection fields to TestObj.col
I'm creating a list of class "Task" in a way such as this.
List<Task> toDoList = new List<Task>;
Task is a base class and have designed it as such:
public class Task : IDetail
{
string _taskName; //Task title.
string _taskDescription; //Task description.
public Task(string tn, string td) //Constructor.
{
_taskName = tn;
_taskDescription = td;
}
// Method set or return _taskName.
public string taskName
{
get
{
return _taskName;
}
set
{
_taskName = value;
}
}
//Method to set or return _taskDescription.
public string taskDescription
{
get
{
return _taskDescription;
}
set
{
_taskDescription = value;
}
}
public virtual void editList()
{
Creator editCreator = new Creator();
editCreator.Show();
}
}
What i've been trying todo is call methods that exists within the inherited class like one the one i have designate "Note" and have defined it as follows.
class Note : Task, IDetail
{
string _noteDescription;
public Note(string nd, string tn, string td) //Constructor.
: base(tn, td)
{
_noteDescription = nd;
}
//Method to set or return _noteDescription.
public string noteDescription
{
get
{
return _noteDescription;
}
set
{
_noteDescription = value;
}
}
public override void editList()
{
noteBuilder editNote = new noteBuilder();
editNote.Show();
}
}
However when i try to call a method of the inherited task on the list i get an error. I am trying to access the method as such:
toDoList.ElementAt(x).noteDescription;
My question is how do i prevent an error from occurring?
the error states
'toDoList.Task' does not contain a definition for 'noteDescription' and no extension method etc etc.
Should i perhaps be declaring the base class as Abstract? or is there something else i am missing?
Many thanks in advance
You've got a List<Task>. That could contain any kind of Task reference - e.g. a different derived type, not a Note. Either you want a List<Note> (so it can all be type-safe), or you'll need to cast the element of the list to Note:
Note note = (Note) toDoList[x];
string description = note.noteDescription;
(Given that you've got a List<T>, you don't need to use ElementAt - use the indexer.)
Filter the list and convert them to notes, like:
var noteList = toDoList.Where(x => x is Note)
.Select(x => (Note)x)
.ToList();
then write
noteList.ElementAt(x).noteDescription;
Because Your list is a list of Task objects, not Note objects.
You'll need to cast your objects to Note objects before you can call methods of the Note class.
(toDoList.ElementAt(x) as Note).noteDescription;
or
toDoList.Cast<Note>().ElementAt(x).noteDescription;
The second option requires all objects in the list be Note objects.
notDescription is a property you have for your derived class. But here you are creating a list of your base class
List<Task> toDoList = new List<Task>;
You can not get the properties of derived class in a base class. IT works the other way. You can access the properties of base class in your child class.
toDoList contains Task elements, not Note elements. Now a Note element is a type of Task element, sure, but polymorphism only works in one direction: you can treat a subclass like its superclass, but you can't treat a superclass like a subclass without casting it first.
If you think about it, you'll realize that it has to be that way. What if you had a second subclass of Task called Foo: you can put both of those types in toDoList...if you tried to access noteDescription on an object that is of type Foo, you'd be in trouble.
However, there is a way to do what you want, it just requires a cast:
var note = toDoList.ElementAt(x) as Note;
var noteDescription = note==null ? "<not a note>" : note.noteDescription;
The other way to do it, of course, would be to move noteDescription into Todo, where it would be accessible from any subclass of Todo, but that's probably not what you want since the name implies that it belongs to Note.