I've just started a project using ASP.NET MVC 3. I'm building on top of an existing object system, so one of the first things I have to do is define display and editor templates for the various types that exist.
Is it possible in MVC to define a DisplayTemplate with a generic argument? For example, we have a BitString<T> class which takes an enumeration as the generic argument and represents a list of options wrapping the supplied enumeration. I'm hoping I can define a single Display/Editor template that handles all BitString instances.
I'm currently using Razor for my views, but I don't mind mixing and matching with ascx (or straight C# if there is a way to do it) to achieve this
Thanks
EDIT:
I think this might be a dup of this question... But it's a year and a half old, so maybe someone has a better answer at this point?
Generic partial view: how to set a generic class as model?
The problem you're describing is a fundamental principal of generics.
ICollection<Object> is not the base class of ICollection<String> even if String is a child class of Object. This is done at compile time, so you basically get two different ICollection class definitions. Therefore they cannot be casted. (Smart people of SO please feel free to correct me on any inaccuracies)
In MVC3 I have worked around this by doing the following:
class Container{
/* Stuff here */
}
class Container<T> : Container{
T Data {get;set;}
}
Then in your view
#model Container
When you need just the common stuff without knowing the generic type.
#model Container<SomeDataType>
When you need the generic type data.
Use Case:
I create a "ModelContainer" class that stores my Model inside, together with an array of Error Messages that can be displayed the page in a partial. Since the partial can be used on every page, it does not know what the Generic type will be, so this workaround is needed.
This cannot be used if you are trying to access the generic data without knowing its type. Hopefully this solves your problem.
I agree with Daryl's answer, but I would just add a small improvement.
interface IContainer{
dynamic Data {get;}
}
class Container<T> : IContainer{
T Data {get;set;}
dynamic IContainer.Data
{
get { return this.Data; }
}
}
Then in your view do the following:
#model IContainer
No, it is not possible to have views with generic type if this generic type is not known. You cannot define a model like this:
#model AppName.Models.BitString<T>
T has to be known:
#model AppName.Models.BitString<SomeEnum>
This being said I would recommend you instead of trying to reuse some models you had in your old system to think of what view models you might put in place and which will be passed to the views.
This might be less than ideal, but you should be able to use
#model BitString<dynamic>
Related
I've tried quite a few different things and have tried every magic Google search word I could think of. If I missed something, feel free to virtually slap me and point out what is probably obvious.
Anyways, I am building an API that, without getting into too many details, will handle a couple different types of order submission. Let's call them type A and B. There are quite a few similarities between those two types, so I made one interface and a parent class to handle them both. I then made two children classes that inherit from the parent class and those children handle all the stuff specific to their respective type. The controller calls the thing that gets the order type, calls something from the parent class, and then calls the appropriate child class. So the idea is:
Interface IOrderSub
Parent class OrderSub - inherits from IOrderSub
Child class OrderSubTypeA - inherits from OrderSub
Child class OrderSubTypeB - inherits from OrderSub
This is where it all breaks down. I am having a rather "fun" time trying to register IOrderSub and those classes. I keep getting an error that I am trying to convert IOrderSub to OrderSub once the code hits:
var app = builder.Build();
in Program.cs.
Things I have tried:
Having the child classes inherit from IOrderSub.
Having the child classes inherit from IOrderSub and OrderSub.
Creating an enum of the order types and using AddTransient<>, Func<>, and a case-switch to determine the order type to register in Program.cs. Visual Studio skips over this whole line when I step through.
public enum ServiceType
{
TypeA,
TypeB,
Parent
}
builder.Services.AddScoped<TypeA>();
builder.Services.AddScoped<TypeB>();
builder.Services.AddScoped<Parent>();
builder.Services.AddTransient<Func<ServiceType, IOrderSub>>
(serviceTypeProvider => key =>
{
switch (key)
{
case ServiceType.TypeA:
return serviceTypeProvider.GetService<OrderSubTypeA>();
case ServiceType.TypeB:
return serviceTypeProvider.GetService<OrderSubTypeB>();
case ServiceType.Parent:
return serviceTypeProvider.GetService<OrderSub>();
default:
return null;
}
});
All different manners of things inside AddScoped<> for the interface and classes.
Having child interfaces that inherit from the parent IOrderSub and having each of the child classes inherit from their respective child interface.
Combinations of the above things.
Various other things I can't remember. The above 6 are what are coming to mind. I've been at this at least a couple days.
I would prefer to keep the class inheritance as I think it just makes sense in this situation due to how similar yet different the two order types are. I did get everything to a point where there are no syntax errors, but I still run into that runtime error.
Anyone have any ideas on how to get this to work, please? I tried to provide as much information as I could, but I'll keep an eye out to see if more is needed.
Thank you!
Thanks to someone asking for the code and my having to go through it with a very fine-toothed comb to remove all references to DB tables and what-not, I realized the issue described above existed between my keyboard and my chair.
I had forgot I had made OrderSub abstract in an attempt to get Visual Studio to stop yelling at me that a method defined in IOrderSub was not in OrderSub (abstract class, defined that method abstract in OrderSub).
I removed any reference to abstract and method overrides and just defined the method as normal. Apparently I had never tried this rather simple solution, as I could just put "new" on the methods in the two child classes and the OrderSub method declaration was effectively "hidden". Not that that is relevant to this. Maybe I'll make a separate question and answer it myself for this issue.
Have a good day all!
Hello denizens of stack overflow, I'm having an issue (perhaps with understanding?) regarding polymorphism and generics. I want to be able to define a "system" that contains a "component". I also want to be able to extend systems and components to be able to have greater functionality.
I currently have two base classes, Component, and I/A_ComponentSystem (For the sake of brevity, I'm not going to be showing any actual code, just definitions):
public abstract class Component { }
public interface IComponentSystem { }
public interface IComponentSystem<TComponent> : IComponentSystem
where TComponent : Component { }
// The following are what should should actually be inherited from
public abstract class AComponentSystem : IComponentSystem { }
public abstract class AComponentSystem<TComponent> : AComponentSystem
where TComponent : Component { }
Below is an example component/system created:
public abstract class ITag : Component { } // This is to allow generating the code in a different binary. Hard to explain in the question, I'll clarify if need be
public class Tag : ITag { }
public abstract class ITagSystem : AComponentSystem<ITag> { }
public class TagSystem : ITagSystem { }
Below are some excerpts of actually trying to use the code/morph between the different objects (please note that the code isn't meant to be used in this way, but I'm writing unit tests to ensure compatibility between layers)
// This is the main system that will be passed around
TagSystem tagSys = new TagSystem();
// This is OK
ITagSystem ITagSys = (ITagSystem)ITagSys;
// This is OK
AComponentSystem A_TagSys = (AComponentSystem)tagSys;
// This is OK
AComponentSystem<ITag> ATag_TagSys = (AComponentSystem<ITag>)tagSys;
// This is OK
IComponentSystem I_TagSys = (IComponentSystem)tagSys;
// This is OK
IComponentSystem<ITag> ITag_TagSys = (IComponentSystem<ITag>)tagSys;
// Even the following is OK (which is why I am confused)
IComponentSystem<Tag> new_ITag_TagSys = (IComponentSystem<Tag>)tagSys;
//***This is where it blows up*** (1)
AComponentSystem<Tag> new_ATag_TagSys = (AComponentSystem<Tag>)tagSys;
I have another interface/class, SystemManager, which is defined thusly:
public interface ISystemManager
{
TComponent AddNewComponentToEntity<TComponent, TComponentSystem>(Entity e) // Please don't ask about Entity, it shouldn't be required for this snippet and I already feel like I've posted a lot)
where TComponent : Component, new() // Required for some reason or I get an error
where TComponentSystem : IComponentSystem<TComponent>;
}
Now, the specific block of code that I have here will throw an error as well:
//*** blows up here as well ***(2)
ISystemManager sysMan = new SystemManager(); // defined elsewhere
sysMan.AddNewComponentToEntity<Tag, ITagSystem>(entity);
As far as the errors that I receive, error (1) is:
Cannot convert type 'TagSystem' to 'AComponentSystem<Tag>'
Error (2) is below:
The type 'ITagSystem' cannot be used as type parameter 'TComponentSystem' in the generic type or method 'ISystemManager.AddNewComponentToEntity<TComponent,TComponentSystem>(Entity)'. There is no implicit reference conversion from 'ITagSystem' to 'IComponentSystem<Tag>'.
Now, as far as my question goes, it is thusly:
Why can I not convert TagSystem to AComponentSystem<Tag>? This seems like a valid morph.
Why is ITagSystem not converting to IComponentSystem<Tag>? It appears that Tag should still conform to ITag, which is supported.
Is there any way I could change my hierarchy while preserving my need for that many layers of abstraction?
Thank you to anyone for reading this and assisting me.
Note: Yes, this is for an EntityFramework driven game engine. I'm building it mainly as an exercise for myself, and so I can quickly spin up 3d projects for myself. Yes, I've built a few game projects before, no I'm not interested in "finishing" a game, I'm just tinkering and having fun.
Without a simpler and yet more-complete code example, it's impossible to provide specific advice in your specific scenario. However, the basic problem is that the types are indeed not convertible, just as the compiler says.
Why can I not convert TagSystem to AComponentSystem<Tag>? This seems like a valid morph.
TagSystem doesn't inherit AComponentSystem<Tag>. It inherits AComponentSystem<ITag>. These two types are not actually the same. Just because Tag inherits/implements ITag, that does not mean that AComponentSystem<Tag> automatically inherits/implements AComponentSystem<ITag>. If it did, then that would mean that a method or property of AComponentSystem<Tag> that normally would return a value of type Tag, could wind up being used in a situation where a Tag value is expected, but some other implementation of ITag is actually returned. This is because you would be able to cast to AComponentSystem<Tag>, and then use that reference to return the non-Tag implementation of ITag, to some code that only wanted Tag.
This is bad for what I hope are obvious reasons, so the compiler doesn't allow you to do that.
Why is ITagSystem not converting to IComponentSystem<Tag>? It appears that Tag should still conform to ITag, which is supported.
Without a good Minimal, Complete, and Verifiable code example, it's difficult to answer this part of your question, as the types you've shown don't appear consistent with the code you've shown. ITagSystem is declared as inheriting AComponentSystem<ITag>, which in turn implements only IComponentSystem, not IComponentSystem<TComponent>.
So based on the code shown, there's no reason even naively to think that the conversion could work. But let's assume for a moment there's a typo in the type declarations you've shown. Then the answer is basically the same as above: implementing IComponentSystem<ITag> is not the same as implementing IComponentSystem<Tag>.
Is there any way I could change my hierarchy while preserving my need for that many layers of abstraction?
Possibly. It depends on what these types actually do. Since C# 4, we've been able to specify generic type parameters on interfaces with covariance and contravariance. With a type parameter thus restricted, and interface members to match, the interface then can support specific casting scenarios like you're trying to do.
But note that this only works when the interface members really are compatible with such conversions. The compiler still won't let you do anything unsafe.
There are a lot of questions on Stack Overflow already discussing this. Technically your question could even be considered a duplicate of those. I hope the above addresses your immediate concerns, and gives you enough information to do more research and see if generic interface variance will work in your situation. If you need more help, I recommend you post a new question and make sure to include a good MCVE that clearly illustrates your question in the simplest way possible.
TagSystem distantly inherits AComponentSystem<ITag>, but you are trying to convert it to AComponentSystem<Tag>. (Note the lack of an "I" in the generic type.) Those two generic types of AComponentSystem<> are completely different, and you cannot freely cast between the two.
Same as point 1, just because Tag is a child of ITag doesn't mean that IComponentSystem<Tag> is a child of IComponentSystem<ITag>.
The answer is almost certainly yes, though exactly how depends entirely on how you are going to use it. You might also want to ask yourself if you really need this many layers of abstraction.
To give a better example of my first point, take for example a common generic type: the List. If generics followed the same inheritance rules as normal classes, then List<Car> would be a subtype of List<Vehicle>. But the difference between the two is that the first list can only hold cars, while the second list can hold any vehicle. So if these lists were parent and child, you would be able to do the following:
List<Car> cars = new List<Car>();
List<Vehicle> vehicles = (List<Vehicle>)cars;
vehicles.Add(new Truck());
You see the problem? The general rules of inheritance just allowed us to add a non-Car object to out list of cars. Or they would, provided that is a legal cast, which it isn't. In reality, List<Car> and List<Vehicle> are not related in any way, but are actually completely separate classes with no direct relation whatsoever.
I have defined some custom helpers in my MVC3 Razor application (ASP.NET) and in the ViewStart code I would like to access my custom helpers.
I noticed that they are not accessible in _ViewStart which then seems understandable as ViewStart derives from ViewStartPage and not WebViewPage.
So I tried to define the helper in a custom ViewStart class but as it turns out I then need access to a ViewDataContainer to be able to initialize the helper.
So, the question is, how can I access my custom helper from ViewStart (or a custom ViewStartPage) and if not, can I then initialize the viewDataContainer constructor property with NULL. I don't expect needing any ViewData access in my custom ViewStartPage.
I also tried implementing the custom ViewStart class but it gives me this error:
CustomViewStart does not implement inherited abstract member 'System.Web.WebPages.WebPageExecutingBase.Execute()'
what should I do in that execute method? I don't want to do anything fancy in the customViewStart, just access my helper.
OK, it is after all possible as I suspected, just needed some nitty gritty technical details sorted out first.
public abstract class CustomViewStartPage : System.Web.Mvc.ViewStartPage {
public Helpers.InvariantHelper ConfigHelper { get; private set; }
public CustomViewStartPage() : base() {
ConfigHelper = new Helpers.InvariantHelper();
}
}
Now, I have defined several custom helpers in my WebViewPage custom base page and they do their work for views. However, in the ViewStart I needed to do certain stuff (here is only a trivial example) that did not require accessing the ViewContext (as I originally thought).
So, with this I can now have this in my _ViewStart.cshtml:
#* Views/_ViewStart.cshtml *#
#inherits MyNamespace.Web.Mvc.CustomViewStartPage
#{
var something = ConfigHelper.DisableParentLayout;
}
Sure, one can also use static members of a class as #MortenMertner indicated (a fresh view at the problem from outside) but in some cases that may not be what you truly want. This example here is senseless but serves as purpose to indicate how it could be accomplished for those who need.
If on the other hand a ViewContext needs to be accessed (another valid scenario) you may want to look at the post in my comment above which describes how to modify this custom view start page to access the context without errors.
From what I understand, the _ViewStart file is not a regular view. It can only be used to set defaults, such as the layout view, for other views.
For instance, this is the complete contents of my _ViewStart file:
#{ Layout = "~/Views/Shared/Layouts/Wide.cshtml"; }
If this holds true there would be no need for custom helpers in the file, and you're likely trying to solve a problem that you shouldn't have in the first place.
As an aside, you can add assemblies and namespaces in Web.config to avoid having to import them in specific views. I use this to import my models, enums and extension methods.
I am fairly new to DI with Autofac and wonder if the following is possible
I want to create a generic controller and action that receives an
injected type.
I do not want an instance of the injected type, but just need its
type, which would be an inplementation of an expected interface.
I would also like to pass that generic type on to a ViewModel, but that is another subject altogether, however if some genious out there can solve both that would be excellent.
public ContractorController<T> : Controller
where T : IContractor{
public ViewResult New() {
var vNewModel = new NewViewModel<T>();
return View(vNewModel);
}
}
This controller should be called through
http://mysite.com/Contractor/New
I have been looking into registering generics with AutoFac, but it
seems that the problem is that the AutofacControllerFactory only implements GetControllerInstance(), expecting the controller Type passed to it from either GetController() or CreateController(), not sure which or what the diffirence is between them. These methods receive the controller's name as a string from RoutData and return the corresponding .NET type which, give the url, http://mysite.com/Contractor/New is controller=Contractor and thus ContractorController cannot be matched by GetController() or CreateController() and therfore passing null to GetControllerInstance() which mean AutofacControllerFactory does not attempt to resolve the type.
I figured that I would have to create a custom Controller Factory
deriving from AutofacControllerFactory, override GetController() or CreateController() and
perform my own mapping from the controller names to the generic types.
Something like
if (controllerName == "Contractor")
return System.Type.GetType(
"UI.Controllers." + controllerName + "Controller`1");
When I debug this I can see that this code is finding the generic controller and returning it.
I thought I could then just register the types like
builder.RegisterType<FakeContractor>().As<IContractor>();
builder.RegisterGeneric(typeof(ContractorController<>));
But I am getting the following error
The Autofac service
'UI.Controllers.ContractorController`1'
representing controller
'ContractorManagement.UI.Controllers.ContractorController`1'
in path '/Contractor/New' has not been registered.
So I think I may be barking up the wrong tree.
Can anyone please shed some light on how I can do this without pulling
my teeth
Thank you
I'm not entirely sure why you want a controller using a generic. Using a generic on a Controller isn't really supported in Mvc - or at least the supporting routing path would be involved. Perhaps you can provide more info on the reasoning behind the approach?
What it looks like is that you want a controller that supports model binding against varying types. The next question is whether these types vary across a common interface or base class.
If that's the case, for Mvc2 check out the IocModelBinder information. This will work with Autofac quite well. This will allow the type to be model bound on post or get allowing you to inject services with autofac.
If you want to vary the types by a common base - supporting a variety of concrete view model - then check out the DerivedTypeModelBinder in MvcContrib. There is a version that works in Mvc 1, 2 and now MvcContrib for Mvc3 has a good sample app to accompany it. The Mvc3 implementation is also faster - speed wasn't a problem before, it's just a more efficient identification process.
Maybe it's not a direct answer to your question, but this is the only possible way to use generic controllers that I ever seen and used:
public abstract class ContractorControllerBase<T> : Controller where T : IContractor {
public ViewResult New() {
var vNewModel = new NewViewModel<T>();
return View(vNewModel);
}
}
public class FakeContractorController : ContractorControllerBase<FakeContractor> {
}
I would like to write code without a lot of switch, if/else, and other typical statements that would execute logic based on user input.
For example, lets say I have a Car class that I want to assemble and call Car.Run(). More importantly, lets say for the tires I have a chocie of 4 different Tire classes to choose from based on the user input.
For the, i dunno, body type, letS say i have 10 body type classes to choose from to construct my car object, and so on and so on.
What is the best pattern to use when this example is magnified by 1000, with the number of configurable parameters.
Is there even a pattern for this ? Ive looked at factory and abstract factory patterns, they dont quite fit the bill for this, although it would seem like it should.
I don't think the factory pattern would be remiss here. This is how I would set it up. I don't see how you can get away from switch/if based logic as fundamentally, your user is making a choice.
public class Car {
public Engine { get; set; }
//more properties here
}
public class EngineFactory {
public Engine CreateEngine(EngineType type {
switch (type) {
case Big:
return new BigEngine();
case Small:
return new SmallEngine();
}
}
}
public class Engine {
}
public class BigEngine : Engine {
}
public class SmallEngine : Engine {
}
public class CarCreator {
public _engineFactory = new EngineFactory();
//more factories
public Car Create() {
Car car = new Car();
car.Engine = _engineFactory.CreateEngine(ddlEngineType.SelectedValue);
//more setup to follow
return car;
}
}
The problem you tell of can be solved using Dependency Injection.
There're many frameworks implementing this pattern (for example, for .NET - excellent Castle.Windsor container).
I think elder_george is correct: you should look into DI containers. However, you might want to check the builder pattern (here too), which deals with "constructing" complex objects by assembling multiple pieces. If anything, this might provide you with some inspiration, and it sounds closer to your problem than the Factory.
You can get around having to use a lot of if or switch statements if you introduce the logic of registration in your factory, a registration entry would add a binding to your dictionary in your factory:
Dictionary<Type,Func<Engine>> _knownEngines;
In the above line, you bind a type to a factory function for example like so:
private void RegisterEngine<TEngineType>(Func<T> factoryFunc) where TEngineType : Engine
{
_knownEngines.Add(typeof(TEngineType), factoryFunc);
}
This would allow you to call:
RegisterEngine<BigEngine>(() => new BigEngine());
on your factory
So now you have a way of allowing your factory to know about a large number of engines without needing to resort to if/switch statements. If all your engines have a parameterless constructor you could even improve the above to:
public void RegisterEngine<TEngineType>() where TEngineType : Engine, new()
{
_knownEngines.Add(typeof(TEngineType), () => new TEngineType());
}
which would allow you to register your engines that your factory can create like so:
RegisterEngine<BigEngine>();
Now we simply need a way of associating a user input to the right type.
If we have some sort of enumeration then, we might might want to map the enum values to their corresponding type. There are many ways to achieve this, either with a dictionary in a similar way as we have done already, but this time it is an enum as a key and a type as a value or by decorating the enum values with their corresponding type as demonstrated here (If you have a very large number of values, this possibility could be interesting)
But, we can skip all this and just take a shortcut and associate the enumeration with the factory function directly.
So we would make our Dictionary look like this:
Dictionary<MyEngineEnumeration,Func<Engine>> _knownEngines;
You would register your engines
public void RegisterEngine<TEngineType>(MyEngineEnumeration key) where TEngineType : Engine, new()
{
_knownEngines.Add(key, () => new TEngineType());
}
like so:
RegisterEngine(MyEngineEnumeration.BigEngine);
And then you would have some sort of create method on your factory class that takes your enumeration value as key:
public Engine ResolveEngine(MyEngineEnumeration key)
{
// some extra safety checks can go here
return _knownEngines[key]
}
So your code would set your
Car.Engine = EngineFactory.ResolveEngine((MyEngineEnumeration)ddlEngine.SelectedValue)
You could follow the same pattern with wheels and so on.
Depending on your requirements, following a registration/resolution approach would allow you to potentially configure your available engines externally in an xml file or a database and allow you to make more engines available without modifying the release code file but by deploying a new assembly which is an interesting prospect.
Good luck!
You could use something like this:
Define a class representing an option within a set of options, ie. a TireType class, BodyType class.
Create an instance of the class for each option, get the data from a store. Fill a collection, ie TireTypeCollection.
Use the collection to fill any control that you show the user for him to select the options, in this way the user selects actually the option class selected.
Use the obejcts selected to build the class.
If any functionality requires chnges in behavior, you could use lamdas to represent that functionality and serialize the representation of the code to save it the store; or you could use delegates, creating a method for each functionality and selecting the correct method and saving it into a delegate on object creation.
What I would consider important in this approach is that any option presented to the user is fully functional, not only a list of names or ids.
You can try the policy class technique in C++.
http://beta.boost.org/community/generic_programming.html#policy
Are you simply asking if you can create an instance of a class based on a string (or maybe even a Type object)?
You can use Activator.CreateInstance for that.
Type wheelType = Type.GetType("Namespace.WheelType");
Wheel w = Activator.CreateInstance(wheelType) as Wheel;
You'd probably want to checking around the classes that you wind up creating, but that's another story.