Good Day,
I have a situation where I'm using code that contains a class called ImportFileContext. The code looks like:
// One of 5 different types can be passed in
public AddImportData(CustomType ModelData)
{
// Depending on which 5 different types, the formatted type will change
FormattedType data = ConvertModelDataToFormattedData(ModelData);
using (var db = new ImportFileContext())
{
// Can this next line be made dynamic?
db.ImportFormattedData.Add(data);
db.SaveChanges();
}
}
Basically, a CustomType will always be passed in to the method. However, there are five different custom types that can be passed in. Depending on which 5 can be passed in, the data will be modified.
Use cases:
Custom Type passed in, format data to a specific format, then add that item to
List of the db instance.
Custom Type 2 passed in, format data to a specific format, then add that item to
List of the db instance.
Custom Type 3 passed in, format data to a specific format, then add that item to
List of the db instance.
So what I'm looking for is a way add an item to the List depending on the data type without having to write several different methods to test which type I'm receiving then adding the item. I know of the strategy pattern and I could use that, but what about adding an item to a list?
I'm really trying to avoid writing code that would look like:
// One of 5 different types can be passed in
public AddImportData(CustomType ModelData)
{
// Depending on which 5 different types, the formatted type will change
FormattedType data = ConvertModelDataToFormattedData(ModelData);
using (var db = new ImportFileContext())
{
if (typeof(ModelData) == "CustomType")
db.ImportFormattedData.Add(data);
elseif (typeof(ModelData) == "CustomType1")
db.ImportCsvData.Add(data);
elseif (typeof(ModelData) == "CustomType2")
db.ImportTabDelimetedData.Add(data);
db.SaveChanges();
}
}
TIA,
coson
I don't know how feasible this is for your application, but you can always add the specific behavior to the CustomType class and subclasses can implement it however they need to.
public class CustomType
{
public virtual void FormatAndWriteToDB(DataBase db);
}
And then sublasses override as needed
public class CustomType1 : CustomType
{
public override void FormatAndWriteToDB(DataBase db)
{
FormattedType data = ConvertModelDataToFormattedData(ModelData);
db.ImportCsvData.Add(data);
}
}
That would make your code very clean in the example method:
public AddImportData(CustomType ModelData)
{
ModelData.FormatAndWriteToDB(db);
db.SaveChanges();
}
Of course you can change this around a bit. For example, if the FormattedType call is common to all of them, you could leave that in the AddImportData method and pass it as an argument to the FormatAndWriteToDB method.
The advantage of this is future additions just require implementing the new subclass of CustomType and no modification is needed to AddImportData.
Sounds to me like you're looking for double-dispatch. You can do this with the Visitor Pattern--which is basically what David Mason detailed--where you decouple the algorithm from the data by putting logic (the visit) into the class that contains the data. That, of course works, but requires you to modify the class outside of the algorithm in order to visit.
I find this complex and it's really just there because statically typed object oriented languages don't normally do runtime overloading. Fortunately in C# 4 they introduced the dynamic keyword which allows use to implement double dispatch much easier--or at least in a way that looks more like method overloading. Which means you create the method overloads, assign the value to dynamic variable, then invoke the method. The method that gets call will be chosen at runtime based on the value. For example:
public static void AddImportData(CustomType ModelData)
{
FormattedType data = ConvertModelDataToFormattedData(ModelData);
using (var db = new ImportFileContext())
{
dynamic temp = ModelData;
ImportData(ModelData, data, db);
}
}
private static void ImportData(CustomType modelData, FormattedType data, ImportFileContext db)
{
db.ImportFormattedData.Add(data);
db.SaveChanges();
}
private static void ImportData(CustomType1 modelData, FormattedType data, ImportFileContext db)
{
db.ImportCsvData.Add(data);
db.SaveChanges();
}
private static void ImportData(CustomType1 modelData, FormattedType data, ImportFileContext db)
{
db.ImportTabDelimetedData.Add(data);
db.SaveChanges();
}
I have more details on my blog at: http://msmvps.com/blogs/peterritchie/archive/2010/05/24/using-the-dynamic-keyword-in-c-to-improve-object-orientation.aspx
Related
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
}
Let's say I have an interface called IConvertableModel and it helps me to convert some MVC models to/from DTO objects as shown below:
public class DisplayEditModel : IConvertableModel<Display>
{
[HiddenInput(DisplayValue = false)]
public int ObjectId { get; set; }
[StringLength(255)]
public string Description { get; set; }
public Display ToDto()
{
return new Display
{
Description = Description,
ObjectId = ObjectId,
};
}
public void SetFromDto(Display dto)
{
Description = dto.Description;
ObjectId = dto.ObjectId;
}
}
But there is one problem with this approach and that is it doesn't allow me do this :
var dto = _dtoRepository.GetFirstDto();
return new DisplayEditModel().SetFromDto(dto);
Instead I should do the following:
var dto = _dtoRepository.GetFirstDto();
var model = new DisplayEditModel();
model.SetFromDto(dto);
return model;
and this is adding extra two lines of code and little bit complexity in the long run.
What I am thinking is to convert SetFromDto method to something like this:
public DisplayEditModel SetFromDto(Display dto)
{
Description = dto.Description;
ObjectId = dto.ObjectId;
return this;
}
I think the benefit of this code is obvious but I also like to learn whether this harms code readability and leads to unexpected results for developers in the long run and if you think anything else, what would you recommend.
Note: Because of the interfaces reasons, I am not thinking to implement a constructor method.
A few thoughts, to begin with:
Adding lines of code is not the same as adding complexity. Having three statements, where each does a simple operation, is not necessarily harder to maintain or understand than a single statement with three operations inside of it.
When a method that begins with Set..., programmers will automatically assume that some stateful values of the target object are going to be changed by this method. It is rare for Set methods to have a return value. Property setters in C# actually "return" the original value passed into them, so you can chain setters:
int i = foo.A = 2;
So the precedent is generally against returning "this" from a set method specifically.
Chaining in general is most useful/desired when you're expecting several operations to be performed, one after the other. For example, C# provides nice initialization syntax so you can "chain" a bunch of different property setters on the same object:
var foo = new Foo { A = 1, B = 2 };
You can see how chaining is fulfilling the need to perform similar, grouped, repetitive operations that typically get performed all together. That is not the problem that you are trying to solve.
If your main gripe is that you don't like having three lines of code, why not just use a helper whose name indicates what you're trying to do?
TModel MapToModel<TModel, TDto>(TDto dto, TModel model)
where TModel : IConvertableModel<TDto>
{
model.SetFromDto(dto);
return model;
}
// usage:
var dto = _dtoRepository.GetFirstDto();
return MapToModel(dto, new DisplayEditModel());
... or even:
TModel CreateModel<TModel, TDto>(TDto dto)
where TModel : IConvertableModel<TDto>, new()
{
var model = new TModel();
return MapToModel(dto, model);
}
// usage:
var dto = _dtoRepository.GetFirstDto();
return CreateModel<DisplayEditModel>(dto);
This is simple, readable, and feasible, whereas the approach you're suggesting would break the IConvertableModel<Display> interface:
public interface IConvertableModel<TDto>
{
public TDto ToDto();
public ??? SetFromDto(TDto dto);
}
What would SetFromDto return? You would have to define another generic type on IConvertableModel.
public interface IConvertableModel<TDto, TModel> {
public TDto ToDto();
public TModel SetFromDto(TDto dto);
}
But this wouldn't really indicate that the SetFromDto method is necessarily returning itself, because it allows for a class that is not a TModel to implement IConvertableModel to convert between two other types.
Now, you could go out of your way to push the generics even farther:
public interface IConvertableModel<TDto, TModel>
where TModel : IConvertableModel<TDto, TModel>
{...}
But this still allows for some fudging, and the interface cannot guarantee that you are really returning "this" object. All in all, I'm not a big fan of that approach.
Rather than having DisplayEditModel have a get/set method for a Display object to get/set the values, just use a property that doesn't actually have a separate backing store:
public Display Display
{
get
{
return new Display
{
Description = Description,
ObjectId = ObjectId,
};
}
set
{
Description = value.Description;
ObjectId = value.ObjectId;
}
}
Now you can use an object initializer with this property when creating a model:
return new DisplayEditModel() { Display = dto };
This is a very javascript way of approaching this problem, though it has it's benefits. In the context of C#, it is a little bit strange though libraries such as LINQ do this to allow chaining together function calls.
My only worry about this, is that this has to be a class that does this consistently. Implementing a chaining function return pattern is not really a convenience as much as it is a design choice. The rule to follow in this case, would be to return this every time you mutate the object.
Chaining also may not be worth it performance wise. Something that can be done by wrapping all those operations into a single function is much faster. For instance:
MyVector.setX(1).SetY(1).SetZ(1).SetW(0)
is a lot slower than simply
MyVector.set(1, 1, 1, 0)
because now you are now doing excessive stack operations to do something fairly simple. It only becomes worth it on very large operations that take up the bulk of the computing time and make sense to chain together. For this reason, LINQ allows you to chain things together.
I wouldn't say that it necessary "harms" or is dangerous. We are in the world of a managed language, so we don't have direct access to that memory location (unlike C/C++). So I would just call it a design choice which can be fairly powerful in some cases and not so much in others.
As noted, chainable methods work fine but are not as common in C# as in some other languages. If the extra lines of code only happen in one place, I'd just leave it alone. If it's really bugging you or you do it a lot, then consider implementing a special constructor for it:
public void DisplayEditModel(Display dto)
{
this.SetFrom(dto);
}
or a static factory method:
public static DisplayEditModel CreateFrom(Display dto)
{
var model = new DisplayEditModel();
model.SetFrom(dto);
return model;
}
Either option has a clear intent, lets you create and return the object in a single line, and is idiomatic. It does require a few extra lines of code in DisplayEditModel, but I doubt it will be a serious problem.
I am working on an application where a form will be created at runtime based on data from a database. It currently uses reflection to create the control and add it to the form.
With this I can easily dynamic create a form at runtime, but next I ran into the issue of how to access the currently selected, eg: TextBox.Text versus DropDownList.SelectedValue. To "fix" this, I created an interface with the method of GetValue. With this, I create a new class and inherit from the respective control and implement the interface.
Now I can easily iterate over the form controls to see if they implement the interface and then get the value of the control.
The question to all of this is: Is this the best way to accomplish this?
To note: I fully expect the controls available to build these forms to get to 15+.
Example of class:
public interface IFormField
{
string GetId();
object GetValue();
}
public TextBox : System.Web.UI.WebControls.TextBox, IFormField
{
public string GetId()
{
return ID;
}
public object GetValue()
{
return Text;
}
}
While I like interfaces, as noted with the "create a new class and inherit from the respective control" .. using new interfaces require that the underlying types are modified. This is not always practical for this case. So, while I won't claim that interfaces aren't appropriate here, I will provide alternative ideas.
This first approach uses a companion object which knows about the control, and how to get the value from the control. This class could use an interface but it is not required here. It allows delaying of the fetcher (in a well-typed manner) but also requires that it's explicit set per companion instance.
interface IWithValue {
string Value { get; }
}
class ControlCompanion<T>: IWithValue where T: Control {
IFunc<Control, string> readValue;
public T Control { get; private set; }
public string Value { get { return readValue(Control); } }
public ControlCompanion (T control, IFunc<T, string> readValue) {
Control = control;
this.readValue = readValue;
}
}
// this is typed narrowly here, but it could be typed wider to
// the actual ControlCompanion if needing additional information
// or actions wrt. the particular control
var valueAccessors = new List<IWithValue>();
var textBox = new TextBox();
valueAccessors.Add(new ControlCompanion(textBox, (c) => c.Text));
var comboBox = new ComboBox();
valueAccessors.Add(new ControlCompanion(comboBox, (c) => c.SelectedValue));
var allValues = valueAccessors.Select(v => v.Value);
Another alternative is to create a function that knows how to extract the values. Because these controls are "created dynamically" (e.g. of type Control) we can't use method overloading directly and must therefore accept the more general type and use some form of reflection or type refinement.
string GetValue(Control c) {
// using this form will allow invalid path detection
TextBox tb;
ComboBox cb;
if ((tb = c as TextBox) != null) {
return tb.Text;
} else if ((cb = c as ComboBox) != null) {
return GetValue(cb);
} else {
throw new Exception("Unsupported control");
}
}
// but we could use overloading once refined ..
string GetValue(ComboBox cb) {
return cb.SelectedValue;
}
Of course, the above two approaches could be combined1 - e.g. a GetValue function that use a per-type extractor (similar to ControlCompanion but independent of a control instance) looked up by a map/dictionary based on the actual type of the control object. If one didn't even want to maintain the map/dictionary manually, assembly reflection could load these per-type extractors automatically - oh, the possibilities and possible complexity!
Along the same lines but more general than the above suggestion is to use Type Converters which is quite a complete (if not complex) setup to handle converting types - even when those types cannot be modified or extended.
There are several different possibilities, and while extending controls and adding interfaces does usually work (it requires the controls can be registered as safe and created by the particular refined implementation), it is limited to cases in which said types can accommodate such changes.
1Okay, here is a rough idea for a general "switchless" GetValue. Note that it separates the control instance from the "fetcher". In fact, such an inversion could even be used to "get companions" to avoid explicit wrapping as in the first example.
interface IFetchValue {
string FetchValue(Control c);
}
abstract class Fetcher<T>: IFetchValue where T : Control {
abstract protected FetchControlValue(T c);
public string FetchValue (Control c) {
return FetchControlValue((T)c);
}
}
class TextBoxFetcher: Fetcher<TextBox> {
protected string FetchControlValue (TextBox tb) {
return tb.Value;
}
}
class ComboBoxFetcher: Fetcher<ComboBox> {
protected string FetchControlValue (ComboBox cb) {
return cb.SelectedValue;
}
}
// This could be initialized via reflection of all
// Fetcher<T>/IFetchValue types with a bit more work.
IDictionary<Type, IFetchValue> map = new Dictionary<Type, IFetchValue> {
{ typeof(TextBox), new TextBoxFetcher() },
{ typeof(ComboBox), new ComboBoxFetcher() },
};
string GetValue(Control c) {
IFetchValue fetcher;
// This should be smarter to also try parent types or
// check general assignability.
if (c != null && map.TryGetValue(c.GetType(), out fetcher)) {
return fetcher(c);
} else {
throw new Exception("Whoops!");
}
}
In addition, your favorite DI/IoC framework might support similar resolve capabilities which would then just push this maintenance into the configuration. Again - many ways, and many ways to make it complicated.
Pretty much. This is one of the main reasons why inheritance/polymorphism are useful. It allows calling code to deal with a generic collection which could actually have many deriving types and deal with them all as if they were the same thing.
If you only have a two or three types it might be simpler to skip this, but as the set of types you can operate on grows this rapidly becomes the best option. Also, I'd like to point out that I don't deal with WinForm types very much, there may already be some support for this type of behavior (which you'd be duplicating) that I don't know about.
You can do it this way (just to state the obvious...), but personally I wouldn't have. Extending a number of controls when all you are doing is adding a single method as part of an interface implementation is a reasonably long winded way to do it.
I would have used a helper method which takes a Control as its input, and checks the type of the control (via casting in lieu of a more language specific option) and then returns the control's value as an object.
The purpose of an interface is to establish a contract irrespective of the actual implementation, so you haven't used it incorrectly, you've just done more work than you really needed to.
Your approach is good and correct if it fullfils your needs and simplifies life.
I want to show an alternative way of control's value retrieval, the way of how it is accomplished in ASP.NET Web Forms itself. This approach could be useful if you don't want to bother with inheritance and if you are using standard input controls or all your controls are decorated with ValidationPropertyAttribute (which is mandatory if you want to use standard validation controls with your custom ones).
To retrieve value of any standard input control we need to use BaseValidator.GetValidationProperty method. This method returns PropertyDescriptor instance for validation property which holds control's value (except ListItem, but this case is covered in code snippet).
So the complete code for value retrieval would be:
public static string GetControlValue(Control c)
{
// This code is copied as-is from BaseValidator.GetControlValidationValue method
PropertyDescriptor prop = BaseValidator.GetValidationProperty(c);
if (prop == null) {
return null;
}
object value = prop.GetValue(c);
if (value is ListItem) {
return((ListItem) value).Value;
}
else if (value != null) {
return value.ToString();
}
else {
return string.Empty;
}
}
Sitting on top of a repository pattern, I have classes for each of my objects (i.e. db tables) to allow for type-based data access:
public abstract class ObjectDataAccessBase<T> : IObjectDataAccess<T>
{
public virtual IQueryable<T> FindAll()
{
...
}
public virtual T Get(int? id)
{
...
}
public virtual void Add(T obj)
{
...
}
public virtual void Delete(T obj)
{
...
}
}
That snippet covers the interface, a common pattern I've seen around. So from another place in the app, what I have is a string for the name of the object (i.e. db table, or "T"), and an int representing the index of the object I want in the table, which I want to pass to "Get(int? id)" to return the object in question. But I need to instantiate the correct class first, casted so as to expose the method I need. I'll need to cast the object, too.
The question is: can that be achieved in this scenario? If so, how?
(More detail on the context of the call: I have a table which relates one kind of object to possibly many other objects, so I have in this table a column with 'string name' for DB table, and an 'int id' for the index of the object in the table, and I want to be able to retrieve the object from the table, properly casted, with these two bits of information. Just testing the waters with this pattern, and already I'm wondering whether it's worthwhile...)
Thanks for your help.
Tim.
Use Reflection to create an instance of your repository:
var type = Type.GetType("ObjectDataAccessBase");
type = type.MakeGenericType(Type.GetType("Your T as string"));
var repository = Activator.CreateInstance(type);
var method = type.GetMethod("Get");
var result = method.Invoke(repository, new object[]{ id });
I'm writing without VS, so there may be a mistake or two. But hopefully the above should get you started.
If you will be using strings a lot I suggest you create a static Dictionary<string, IObjectDataAccess> and instantiate all repositories explicitly.
I am working on an ASP.Net MVC website and I am stuck on a getting my C# code using generics to play nice with my views.
I have a Controller that passes a Model to a View (so far so good). The Model is of type IDescribedEnumerable<T> with some constraints on T, among those is the constraint that T inherits from an interface (IDescribedModel).
I can easily write a View that accepts an IDescribedEnumerable<Country> and that will work as long as T is in fact the type Country.
However, I'd also like to write a default view that accepts an IDescribedEnumerable of <<whatever>> and that will render it. This should be entirely possible. I don't always need to know the specific type of the Model. Often just knowing that it's an IDescribedModel is enough.
As long as I stay in C# there is no problem. When I don't care about the specific type I just declare methods and objects as accepting a <T>. When I do care I declare them as accepting Country.
But:
(1) If I want to render a View I have to pick an type. I can't just say Inherits="System.Web.Mvc.ViewUserControl<IDescribedEnumerable<T>>" I have to specify an existing type between the <>. (even if I were to inherit from ViewUserControl I'd have to cast it to an IDescribedEnumerable<<something>>.
(2) Ideally I'd say that Model is IDescribedEnumerable<IDescribedModel> in the default View and IDescribedEnumerable<Country> in the specific implementation. However, then my Controller needs to know whether he's going to render to the default View or the specific view. It is not possible to simply cast an object that is IDescribedEnumerable<Country> to IDescribedEnumerable<IDescribedModel>. (IIRC it is possible in C# 4, but I'm using 3.5)
So what should I do? All options I can think of are very sub-optimal (I'm not looking forward to removing the generics and just casting objects around, nor to copy pasting the default view 65 times and keeping the copies synchoronized, nor going reflection gallore and creating an object based on a known Type object)
while awaiting some C# genius to come along with the answer to all my problems I have implemented the trick that IEnumerable also uses:
I added a method public IDescribedEnumerable<IDescribedModel> AsIDescribedModels() to the IDescribedEnumerable interface and created a new class GenericDescribedEnumerable<T> : IDescribedEnumerable<IDescribedModel>. In my DescribedEnumerable<T> class I create a GenericDescribedEnumerable and return that. In the GenericDescribedEnumerable I return this
in full code:
public interface IDescribedModel<T> : IDescribedModel{
T original {
get;
}
}
public interface IDescribedEnumerable {
IDescribedEnumerable<IViewModel> AsIViewModels();
}
public interface IDescribedEnumerable<T> : IDescribedEnumerable
where T : IDescribedModel{
IEnumerable<T> GetViewModels();
}
public class DescribedEnumerable<T> : IDescribedEnumerable<IDescribedModel<T>>{
public DescribedEnumerable(IEnumerable<T> enumerable) {}
public IDescribedEnumerable<IViewModel> AsIViewModels() {
return new GenericDescribedEnumerable<T>(/*allProperties*/);
}
public IEnumerable<T> GetViewModels() {
foreach ( T obj in _enumerable ) {
var vm = new DescribedModel<T>( obj);
yield return vm;
}
}
}
public class GenericDescribedEnumerable<T> : IDescribedEnumerable<IViewModel>{
//pass in the constructor everything you need, or create in the
//constructor of DescribedEnumerable<T>
public GenericDescribedEnumerable(/*allProperties*/) {
}
public IEnumerable<IViewModel> GetViewModels() {
foreach ( T obj in _enumerable ) {
var vm = new PlatoViewModel<T>( obj );
yield return vm;
}
}
public IDescribedEnumerable<IViewModel> AsIViewModels() {
return this;
}
}
Yeah, that will work or use the model as object, and cast it appropriately. That's the approach the ViewPage class uses, with ViewPage and ViewPage : ViewPage.
Inherits="System.Web.Mvc.ViewUserControl<IDescribedEnumerable<T>>"
...
Model.Cast<IModel>()