I have an m-to-n association between source and target formats. (right now, m=2 and n=5, with n growing faster than m).
I want to get an event, the input format being an Item
or DbDataReader
, and convert it into other types, which shall provide the required constructors:
public MyEvent(Item item)
public MyEvent(DbDataReader ddr)
public MyEventDetailed(Item item)
public MyEventDetailed(DbDataReader ddr)
public MyEventInfo(Item item)
public MyEventInfo(DbDataReader ddr)
public MyEventNotification(Item item)
public MyEventNotification(DbDataReader ddr)
public MyEventReminder(Item item)
public MyEventReminder(DbDataReader ddr)
Each constructors is to be used by exactly one of the two DataStores:
EwsDataStore : DataStoreBase
DbDataStore : DataStoreBase
which right now each implement the abstract getEvent
method from the DataStoreBase
:
abstract MyEventDetailed getEvent(string uniqueId);
Now I need all the other target formats as well, so I want to make them generic like this:
abstract T getEvent<T>(string uniqueId) where T : IEvent, new()
with a possible EwsDataStore implementation being
getEvent<T>(string uniqueId) where T : IEvent, new() // TODO: All affected models have to implement IEvent interface
{
Item item;
try {
item = Item.Bind(service, new ItemId(uniqueId));
} catch(Exception e) {
throw new ArgumentException("An item by that Id was not found in the data store", "uniqueId", e);
}
// return T.FromItem(item); // Needs static IEvent.FromItem method.
return new T(item); // IEvent has to enforce constructor with parameter Item on all implementing classes
}
and for Sql:
getEvent<T>(string uniqueId) where T:IEvent, new() // TODO: All affected models have to implement IEvent interface
{
SQL db = new SQL();
db.AddParameter("@uniqueId", uniqueId)
SqlDataReader sdr = db.ExecuteReader("SELECT * FROM datastore WHERE uniqueId = @uniqueId");
if(!sdr.HasRows) throw new ArgumentException("An item by that Id was not found in the data store");
sdr.Read();
// return T.FromDdr(sdr); // Needs static IEvent.FromDdr method.
return new T(sdr); // IEvent has to enforce constructor with parameter DataReader on all implementing classes
}
But neither a constructor with parameters, nor a static method would be allowed on the generic type, each throwing one of the following two error messages:
The modifier 'static' is not valid for this item
'T': cannot provide arguments when creating an instance of a variable type
Searching for these error messages; I found that "the instance method can simply (sic!) delegate to a static method", or I can use Reflection
or Activator
.
None of them seems sufficiently easy/straightforward to write, understand, use and maintain.
Is there a straightforward way to use inheritance and generics to create all the different types based on the type I provide, which can be understood/followed by other programmers even if they are not proficient in-depth in C# inheritance?