I have have attempted to use generics and constraints to create functions that retrieve and save data from a number of similar objects. Each of these objects describe their own properties. When I use these methods for a particular Type I don't understand why I have to specify new() in the constraint and also create a new version of the type in order to access its underlying properties to assist me. I'm sure there is a better way, but my knowledge in this area is a little lacking.
There are a number of objects that inherit from RawDataAggregatedItem.
public class Project : RawDataAggregatedItem
{
public override string IdColumnName
{
get { return "project_id"; }
}
public override string DescriptionColumnName
{
get { return "project_description"; }
}
public override string GetStoredProcedureName
{
get { return "R_projects_sp"; }
}
}
...
public class Category : RawDataAggregatedItem
{
public override string IdColumnName
{
get { return "asset_category"; }
}
public override string GetStoredProcedureName
{
get { return "R_asset_category_sp"; }
}
}
RawDataAggregatedItem has it's own interface:
public interface IRawDataAggregatedItem
{
string IdColumnName { get; }
string DescriptionColumnName { get; }
}
public abstract class RawDataAggregatedItem : IRawDataAggregatedItem
{
public abstract string IdColumnName { get; }
public virtual string DescriptionColumnName
{
get { return string.Empty; }
}
public abstract string GetStoredProcedureName { get; }
}
I've created functions that get and save data to the database using generics expecting these different object types:
public RawDataAggregatedItems<T> GetRawDataAggregated<T>(int? id) where T : IRawDataAggregatedItem, new()
{
try
{
var itemType = new T();
using (var cn = Connection())
{
var cmd = new SqlCommand(itemType.GetStoredProcedureName, cn) { CommandTimeout = _commandTimeout, CommandType = CommandType.StoredProcedure };
cmd.Parameters.Add(new SqlParameter("@periodId", SqlDbType.Int)).Value = id;
return new RawDataAggregatedItems<T>(cmd.ExecuteReader());
}
}
catch (Exception ex)
{
throw new Exception("Error fetching aggregated rawdata list.", ex);
}
}
public void UpdateRawDataAggregated(RawDataAggregatedItem itemToUpdate)
{
try
{
using (var cn = Connection())
{
var cmd = new SqlCommand(itemToUpdate.UpdateStoredProcedureName, cn) { CommandTimeout = _commandTimeout, CommandType = CommandType.StoredProcedure };
cmd.Parameters.Add(new SqlParameter("@projectid", SqlDbType.VarChar)).Value = ((IRawDataAggregatedItem)itemToUpdate).ID;
cmd.Parameters.Add(new SqlParameter("@is_flagged", SqlDbType.Bit)).Value = ((IRawDataAggregatedItem)itemToUpdate).isFlaggedForReview;
cmd.Parameters.Add(new SqlParameter("@is_reviewed", SqlDbType.Bit)).Value = ((IRawDataAggregatedItem)itemToUpdate).isReviewed;
cmd.ExecuteReader();
}
}
catch (Exception ex)
{
throw new Exception("Error updating aggregated rawdata item.", ex);
}
}
If feels a bit wrong to
- supply
new()
in theGetRawDataAggregated
constraint but the compiler is forcing me to. - New-ing up a Type
T
(var itemType = new T()
) in order to get toT.Property
.
Please could you suggest a better way of doing this?