I am writing a tranformer that takes some input and gives an output.I need to call a specific tranformer based on my input type.
public static myentrypoint( template t);
{
//I could do something like this.
switch(t)
{
case t1:
transformt1(..);
case t2:
transformt1(..);
....
}
}
Trasform1 : Itransform
{
tranform1(...);
}
Trasform2 : Itransform
{
tranform2(...);
}
I need to map which function to call based on what my template is. I can do a switch but are there more cleaner ways to do this using some design patterns ? I was thinking a of writing a static dictionary. I am new to OOP so any suggestions would be great.
If template is a class, and each template potentially has a different transform, then why not just include the transform function inside of your template class?
public static myentrypoint( ITemplate t);
{
t.transform();
}
The way that I do these types of situations is through the use of Generics. (Shameless self-promotion of a blog post)
Basically, you'll have your base class set up like this:
public abstract class Transformer<T>
where T : Template
{
public abstract void Transform(T item);
}
Then you derive for each of your types like this:
public class Transformer1 : Tansformer<Template1>
{
public void Transform(Template1 item)
{
}
}
public class Transformer2 : Transformer<Template2>
{
public void Transform(Template2 item)
{
}
}
Then you'll just need a factory to give you the correct Transformer.
public class TransformFactory
{
public Transformer<T> GetTransformer<T>(T item)
{
if (item is Template1)
return new Transformer1();
else if (item is Template2)
return new Transformer2();
// ...
}
}
The benefit of this approach is that you'll be able to encapsulate all behavior on that specific type in the concrete implementations. If there is any common behavior on them all, you can do that in the abstract base.
Invoking methods based on a parameter without switch-case statements in C#
In OOP, based on the [open/close principle] which says that software entities such as classes and functions should be open for extension, but closed
for modification.
Methods which use switch-case statement would call this principle into question. In order to implement this principle inside the codes without
causing changes in their functionality.
We use a pattern named "Delegate Dictionary Pattern".
For example, we have an entity named Template that keep input values as well as some of Transform classes for processing this Template.
Template class for keeping input value
public class Template
{
public int TransformNo { get; set; }
public string Title { get; set; }
}
ITransform interface for transform abstract
public interface ITransform
{
void Do(Template template);
}
Transform1 as a concrete class of ITransform
public class Transform1 : ITransform
{
public void Do(Template template)
{
Console.WriteLine($"Transform : {template.TransformNo}, TemplateTitle : { template.Title}");
}
}
Transform2 as a concrete class of ITransform
public class Transform2 : ITransform
{
public void Do(Template template)
{
Console.WriteLine($"Transform : {template.TransformNo}, TemplateTitle : { template.Title}");
}
}
TransformCordinator class for coordinating template of *ITransformer**
public class TransformCordinator
{
Dictionary<int, Action<Template>> transformMap = new Dictionary<int, Action<Template>>();
public TransformCordinator()
{
transformMap.Add(1, x => new Transform1().Do(x));
transformMap.Add(2, x => new Transform2().Do(x));
}
public void Do(Template template)
{
transformMap[template.TransformNo](template);
}
}
// example
class Program
{
static void Main(string[] args)
{
var transformCordinator = new TransformCordinator();
transformCordinator.Do(new Template() { TransformNo = 1, Title = "Hi!" });
Console.ReadLine();
}
}
Related
I have the following classes
public abstract class BaseViewPresenter { }
public abstract class BaseView<T> : UserControl
where T : BaseViewPresenter { }
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter> { }
I have a method that looks like this (simplified)
public BaseView<BaseViewPresenter> Resolve(BaseViewPresenter model)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
// Correctly creates BaseView object
var control = Activator.CreateInstance(viewType);
// Fails to cast as BaseView<BaseViewPresenter> so returns null
return control as BaseView<BaseViewPresenter>;
}
When I call this using an instances of LoginPresenter
var login = new LoginPresenter();
var ctl = Resolve(login);
The line Activator.CreateInstance(viewType) correctly resolves into a new instances of my LoginView, however control as BaseView<BaseViewPresenter> can't do the cast correctly so returns null.
Is there a way to correctly cast the control into BaseView<BaseViewPresenter> without using specific type generics?
Since LoginView inherits from BaseView<LoginPresenter>, and LoginPresenter inherits from BaseViewPresenter, I would assume there's a way to convert LoginView to BaseView<BaseViewPresenter>.
I am stuck with using .Net 3.5
This is a very frequently asked question. Let's rename your types:
abstract class Fruit { } // was BaseViewPresenter
abstract class FruitBowl<T> where T : Fruit // was BaseView
class Apple : Fruit { } // was LoginPresenter
class BowlOfApples : FruitBowl<Apple> { } // was LoginView
Your question now is:
I have a BowlOfApples, which inherits from FruitBowl<Apple>. Why can I not use it as a FruitBowl<Fruit>? An apple is a fruit, so a bowl of apples is a bowl of fruit.
No, it isn't. You can put a banana in a bowl of fruit, but you can't put a banana in a bowl of apples, and therefore a bowl of apples is not a bowl of fruit. (And by similar argument, a bowl of fruit is not a bowl of apples either.) Since the operations you can legally perform on the two types are different, they cannot be compatible.
Here is a photo of StackOverflow legend Jon Skeet demonstrating this fact:
The feature you want is called generic contravariance, and it is supported only on interfaces and delegate types when the compiler can prove that the variance is safe, and when the varying type is a reference type. For example, you can use an IEnumerable<Apple> in a context where IEnumerable<Fruit> is needed because the compiler can verify that there is no way that you can put a Banana into a sequence of fruit.
Do a search on "C# covariance and contravariance" on this site or on the web and you'll find many more details about how this feature works. In particular, my series of articles on how we designed and implemented this feature in C# 4 starts here: http://blogs.msdn.com/b/ericlippert/archive/2007/10/16/covariance-and-contravariance-in-c-part-one.aspx
I accepted Eric's answer since it provides a great explanation of why what I wanted wasn't possible, but I also thought I'd share my solution in case anyone else runs into this same problem.
I removed the generic type parameter from my original BaseView class, and created a 2nd version of the BaseView class that included the generic type parameter and specifics for it.
The first version is used by my .Resolve() method or other code that doesn't care about the specific types, and the second version is used by any code that does care, such as the implentation of a BaseView
Here's an example of how my code ended up looking
// base classes
public abstract class BaseViewPresenter { }
public abstract class BaseView : UserControl
{
public BaseViewPresenter Presenter { get; set; }
}
public abstract class BaseView<T> : BaseView
where T : BaseViewPresenter
{
public new T Presenter
{
get { return base.Presenter as T; }
set { base.Presenter = value; }
}
}
// specific classes
public class LoginPresenter : BaseViewPresenter { }
public partial class LoginView : BaseView<LoginPresenter>
{
// Can now call things like Presenter.LoginPresenterMethod()
}
// updated .Resolve method used for obtaining UI object
public BaseView Resolve(BaseViewPresenter presenter)
{
var type = model.GetType();
var viewType = _dataTemplates[type];
BaseView view = Activator.CreateInstance(viewType) as BaseView;
view.Presenter = presenter;
return view;
}
You're expecting to treat the type as being covariant with respect to the generic argument. Classes can never be covariant; you'd need to use an interface rather than (or in addition to) an abstract class to make it covariant with respect to T. You'd also need to be using C# 4.0.
My usual solution to this problem is to create an intermediary class that has access to the type-parametric class's methods through delegates. Fields can also be accessed through getters/setters.
The general pattern goes:
public abstract class Super {}
public abstract class MyAbstractType<T> where T : Super {
public MyGeneralType AsGeneralType() {
return MyGeneralType.Create(this);
}
// Depending on the context, an implicit cast operator might make things
// look nicer, though it might be too subtle to some tastes.
public static implicit operator MyGeneralType(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
public int field;
public void MyMethod1() {}
public void MyMethod2(int argument) {}
public abstract bool MyMethod3(string argument);
}
public delegate T Getter<T>();
public delegate void Setter<T>(T value);
public delegate void MyMethod1Del();
public delegate void MyMethod2Del(int argument);
public delegate bool MyMethod3Del(string argument);
public class MyGeneralType {
public Getter<int> FieldGetter;
public Setter<int> FieldSetter;
public MyMethod1Del MyMethod1;
public MyMethod2Del MyMethod2;
public MyMethod3Del MyMethod3;
public static MyGeneralType Create<T>(MyAbstractType<T> t) where T : Super {
var g = new MyGeneralType();
g.FieldGetter = delegate { return t.field; };
g.FieldSetter = value => { t.field = value; };
g.MyMethod1 = t.MyMethod1;
g.MyMethod2 = t.MyMethod2;
g.MyMethod3 = t.MyMethod3;
return g;
}
public int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
The above exemplifies getting all the methods and fields but normally I only need a few of them. This is a general solution to the problem and one could feasibly write a tool to generate these intermediary classes automatically, which I might at some point.
Try it here: https://dotnetfiddle.net/tLkmgR
Note that this is enough for all my cases, but you can be extra hacky with this:
public abstract class MyAbstractType<T> where T : Super {
// ... Same everything else ...
// data fields must become abstract getters/setters, unfortunate
public abstract int field {
get;
set;
}
public static implicit operator MyAbstractType<Super>(MyAbstractType<T> t) {
return MyGeneralType.Create(t);
}
}
public class MyGeneralType : MyAbstractType<Super> {
// ... same constructors and setter/getter
// fields but only keep method fields
// that contain the method references for
// implementations of abstract classes,
// and rename them not to clash with the
// actual method names ...
public MyMethod3Del myMethod3Ref;
// Implement abstract methods by calling the corresponding
// method references.
public override bool MyMethod3(string argument) {
return myMethod3Ref(argument);
}
// Same getters/setters but with override keyword
public override int field {
get { return FieldGetter(); }
set { FieldSetter(value); }
}
}
And there you go, now you can literally cast a MyAbstractType<Sub> where Sub : Super to a MyAbstractType<Super>, although it's no longer the same object anymore, but it does retain the same methods and data, it's sort of a complex pointer.
public class Sub : Super {}
public class MySubType : MyAbstractType<Sub> {
public int _field;
public override int field {
get { return _field; }
set { _field = value; }
}
public override bool MyMethod3(string argument) {
Console.WriteLine("hello " + argument);
return argument == "world";
}
}
public class MainClass {
public static void Main() {
MyAbstractType<Sub> sub = new MyAbstractType<Sub>();
MyAbstractType<Super> super = sub;
super.MyMethod3("hello"); // calls sub.MyMethod3();
super.field = 10; // sets sub.field
}
}
This isn't as good in my opinion, the other version of MyGeneralType is a more straighforward layer over the concrete types, plus it doesn't require rewriting the data fields, but it does actually answer the question, technically. Try it here: https://dotnetfiddle.net/S3r3ke
Example
Using these abstract classes:
public abstract class Animal {
public string name;
public Animal(string name) {
this.name = name;
}
public abstract string Sound();
}
public abstract class AnimalHouse<T> where T : Animal {
List<T> animals;
public AnimalHouse(T[] animals) {
this.animals = animals.ToList();
}
public static implicit operator GeneralAnimalHouse(AnimalHouse<T> house) {
return GeneralAnimalHouse.Create(house);
}
public List<string> HouseSounds() {
return animals.Select(animal => animal.Sound()).ToList();
}
}
We make this "general" variant:
public delegate List<string> HouseSoundsDel();
public class GeneralAnimalHouse {
public HouseSoundsDel HouseSounds;
public static GeneralAnimalHouse Create<T>(AnimalHouse<T> house) where T : Animal {
var general = new GeneralAnimalHouse();
general.HouseSounds = house.HouseSounds;
return general;
}
}
And finally with these inheritors:
public class Dog : Animal {
public Dog(string name) : base(name) {}
public override string Sound() {
return name + ": woof";
}
}
public class Cat : Animal {
public Cat(string name) : base(name) {}
public override string Sound() {
return name + ": meow";
}
}
public class DogHouse : AnimalHouse<Dog> {
public DogHouse(params Dog[] dogs) : base(dogs) {}
}
public class CatHouse : AnimalHouse<Cat> {
public CatHouse(params Cat[] cats) : base(cats) {}
}
We use it like this:
public class AnimalCity {
List<GeneralAnimalHouse> houses;
public AnimalCity(params GeneralAnimalHouse[] houses) {
this.houses = houses.ToList();
}
public List<string> CitySounds() {
var random = new Random();
return houses.SelectMany(house => house.HouseSounds())
.OrderBy(x => random.Next())
.ToList();
}
}
public class MainClass {
public static void Main() {
var fluffy = new Cat("Fluffy");
var miu = new Cat("Miu");
var snuffles = new Cat("Snuffles");
var snoopy = new Dog("Snoopy");
var marley = new Dog("Marley");
var megan = new Dog("Megan");
var catHouse = new CatHouse(fluffy, miu, snuffles);
var dogHouse = new DogHouse(snoopy, marley, megan);
var animalCity = new AnimalCity(catHouse, dogHouse);
foreach (var sound in animalCity.CitySounds()) {
Console.WriteLine(sound);
}
}
}
Output:
Miu: meow
Snoopy: woof
Snuffles: meow
Fluffy: meow
Marley: woof
Megan: woof
Notes:
I added names so it's clear that the method references carry their owner's data with them, for those unfamiliar with delegates.
The required using statements for this code are System, System.Collections.Generic, and System.Linq.
You can try it here: https://dotnetfiddle.net/6qkHL3#
A version that makes GeneralAnimalHouse a subclass of AnimalHouse<Animal> can be found here: https://dotnetfiddle.net/XS0ljg
Currently I am in the phase of refactoring my code after it has been unit tested, and I have some concerns about the refactoring from a design point of view with regards to type safety. My original code looked a bit like this:
Interfaces
public interface IBase
{
int ID { get; set; }
}
public interface IFirstSub : IBase
{
string Description { get; set; }
}
public interface ISecondSub : IBase
{
decimal Total { get; set; }
}
public interface IThirdSub : IBase
{
int Count { get; set; }
}
public interface IBaseContainer
{
void Add(IBase baseParam);
}
Implementations
public class FirstContainer : IBaseContainer
{
public void Add(IBase baseParam)
{
if (!(baseParam is IFirstSub || baseParam is ISecondSub))
{
throw new ArgumentException(nameof(baseParam));
}
// Do Something
}
}
public class SecondContainer : IBaseContainer
{
public void Add(IBase baseParam)
{
if (!(baseParam is IThirdSub))
{
throw new ArgumentException(nameof(baseParam));
}
// Do Something
}
}
With my original implementation of FirstContainer and SecondContainer, it was repeating the same logic at the start of the Add method, so I thought I would refactor the code to look something like this:
public abstract class BaseContainer : IBaseContainer
{
private readonly List<Type> _types = new List<Type>();
protected BaseContainer(params Type[] baseTypes)
{
_types.AddRange(baseTypes);
}
public void Add(IBase baseParam)
{
if (_types.All(type => !type.IsInstanceOfType(baseParam)))
{
throw new ArgumentException(nameof(baseParam));
}
DoSomething(baseParam);
}
protected abstract void DoSomething(IBase baseParam);
}
public class ThirdContainer : BaseContainer
{
public ThirdContainer() : base(typeof(IFirstSub)) { }
protected override void DoSomething(IBase baseParam)
{
// Do Something
}
}
With this refactoring done, it successfully removes the duplication of the code from the start of the Add method, but my main concern with the refactoring is the fact that the call to the base constructor base(typeof(IFirstSub)) is not really type safe. By that, I mean I can call the base constructor like base(typeof(object)) for example, and it will compile. For the purposes of my project, I'd like to constrain the types to ones that inherit IBase, and enforce at compile time.
Is there anyway to overcome this limitation, or would a new design be needed in order to achieve this?
No it's not type safe
Passing and validating types at run-time is not type-safe, as type-safety is a compile-time concept. In my opinion your refactoring effort does not improve the code, and in fact does something quite weird.
Function overloading
If you need a method that accepts either of two types, you can use function overloading:
public class FirstContainer : IBaseContainer
{
public void Add(IFirstSub param)
{
// Do Something
}
public void Add(ISecondSub param)
{
// Do Something
}
}
The compiler will automatically choose the right prototype for you, and will not allow anything other than an IFirstSub or ISecondSub.
Create another interface
Another approach requires you to add an interface for the types that have something in common, like this:
interface ICanBeHeldInFirstContainer
{ }
public interface IFirstSub : IBase, ICanBeHeldInFirstContainer
{
string Description { get; set; }
}
public interface ISecondSub : IBase, ICanBeHeldInFirstContainer
{
decimal Total { get; set; }
}
Then you do this:
public class FirstContainer : IBaseContainer
{
public void Add(ICanBeHeldInFirstContainer param)
{
// Do Something
}
}
or this:
public class FirstContainer : IBaseContainer
{
public void Add<T>(T param) where T : ICanBeHeldInFirstContainer
{
// Do Something
}
}
Is there a way to have a generic field in a class to specialize to a specific type in the constructor?
For example:
class concreteClass1
{
private int a;
public concreteClass1( int a)
{
this.a = a;
}
}
class concreteClass2
{
string b;
public concreteClass2(string b)
{
this.b = b;
}
}
class A<T>
{
private T field;
public A(int x)
{
field = new concreteClass1(x); //error here CS0029
}
public A(string y)
{
field = new concreteClass2(y); //error here CS0029
}
}
So T can be either concreteClass1 or concreteClass1 and their respective ctors will have different signatures.
I would refactor this to use dependency injection. That way the class doesn't contain code to create other classes that it depends on, like myConcreteField = new ConcreteA<T>(4);. Dependency injection is used to keep code from getting tied into difficult knots like this.
(Your example is very, very abstract, which makes it a little difficult. If you use class names like "Concrete" and "Implementation" then it makes the answer harder to read because we use those same words to describe concepts.)
Instead, whatever that Concrete thing is, declare an interface, like
public interface ISomethingThatTheOtherClassNeeds<T>
{
public int MySomething {get;set;}
}
public class SomethingThatTheOtherClassNeeds : ISomethingThatTheOtherClassNeeds<string>
{
public int MySomething {get;set;}
}
Then in your Implementation class:
class Implementation<T>
{
private readonly ISomethingThatTheOtherClassNeeds<T> _something;
public Implementation(ISomethingThatTheOtherClassNeeds<T> something)
{
_something = something;
}
void DoSomething()
{
Console.Write(_something.MySomething.ToString());
}
}
The difference is that instead of being responsible for creating whatever that class is, it's passed to Implementation in the constructor. Implementation doesn't even know what the class is - it just knows that it matches the interface.
This is especially helpful if those other classes in turn depend on more classes. If you're creating them by calling new in your class then that class has to know how to create those classes.
Then to wire it up you would use a dependency injection container like Windsor, Unity, Autofac, and many more. That's not very commonly done with console applications, but I'm guessing this is more experimental than real.
Well this was a bit tricky due to having to convert types. Maybe this will work for you?
class Program
{
static void Main(string[] args)
{
var myImplementation = new Implementation<int>(4);
var myImplementation2 = new Implementation<string>("Hello World");
Console.WriteLine(myImplementation.myConcreteField); // outputs 4!
Console.WriteLine(myImplementation2.myConcreteField); // outputs Hello World
}
}
abstract class MyAbstract<T>
{
public T MySomething;
public MyAbstract(T something)
{
MySomething = something;
}
}
class ConcreteA<T> : MyAbstract<T>
{
public ConcreteA(int something) : base((T)Convert.ChangeType(something, typeof(T)))
{
}
}
class ConcreteB<T> : MyAbstract<T>
{
public ConcreteB(string something) : base((T)Convert.ChangeType(something, typeof(T)))
{
}
}
class Implementation<T>
{
public MyAbstract<T> myConcreteField;
public Implementation(T a)
{
myConcreteField = new ConcreteA<T>(4);
}
void DoSomething()
{
Console.Write(myConcreteField.MySomething.ToString());
}
}
I'm having a hard time describing to problem in the title, sorry if the title isn't the clearest.
Suppose I have the following interface/classes :
public interface IAction { /*...*/ }
public class WriteAction : IAction { /*...*/ }
public class ReadAction : IAction { /*...*/ }
Now, these actions will be used in other classes. ReadWriteTest can have both ReadAction and WriteAction objects, but ReadTest can only have ReadAction objects.
Note that these test objects do more than just this, I'm redacting other functionalities as they are not pertinent to the question.
Both xxxTest classes share a common interface. So the implementation of the interface and ReadWriteTest class is as follows:
public interface ITest
{
List<IAction> Actions { get; set; }
}
public class ReadWriteTest : ITest
{
public List<IAction> Actions { get; set; }
}
The problem is that for the ReadTest class, I would like to limit this property to only contain ReadAction elements.
What I tried to implement is the following:
public class ReadTest : ITest
{
public List<ReadAction> Actions { get; set; }
}
It seems to me that this should work, as every ReadAction inherently implements the IAction interface.
However, the compiler doesn't like it, and tells me the ReadTest class doesn't implement all needed IAction properties.
Is there a way to restrict the content of this Actionlist in the ReadTest class definition?
I can work around it by creating a custom AddAction(IAction action) method that simply does not add any WriteAction objects, but I was hoping for a more elegant solution to this problem.
Is this possible?
Update on the final result
As answered, it can be done by adding a generic type to the interface. This solves the problem I'm describing, but sadly does not solve the larger problem. Adding this generict type means that I now can't address either Test object as an ITest, as I'm now required to specify the generic parameter, which is different for either Test.
The solution (or at least, my solution) is to remove the Actions property from the ITest interface. The Actions properties still exist in the classes.
Instead of having the list property defined in the interface, I added a Run() method to the interface. This method will iterate over the locally defined Actions list in either Test class.
So as a quick overview:
foreach(ITest myTest in myTests)
{
myTest.Run()
}
Class implementation for ReadWriteTest:
public List<IAction> Actions {get; set;}
public void Run()
{
foreach(IAction action in Actions) { /*...*/ }
}
Class implementation for ReadTest:
public List<ReadAction> Actions {get; set;}
public void Run()
{
foreach(IAction action in Actions) //I could also declare it as a ReadAction. Either works.
{ /*...*/ }
}
You could fix this by using a generic type in your ITest interface:
public interface ITest<T> where T : IAction
{
List<T> Actions { get; set; }
}
Note the type constraint which forces the passed in type to be IAction. This in turn makes your subclasses this:
public class ReadWriteTest : ITest<IAction>
{
public List<IAction> Actions { get; set; }
}
public class ReadTest : ITest<ReadAction>
{
public List<ReadAction> Actions { get; set; }
}
If you can accept changing the interface so that you can't set the actions directly via the property, then you can make the class covariant by using the out keyword.
This will then allow you to create, for example, an object of type ReadWriteTest and pass it to a method which accepts a parameter of type ITest<IAction>.
Here's a complete compilable console app to demonstrate:
using System;
using System.Collections.Generic;
namespace Demo
{
// The basic IAction interface.
public interface IAction
{
void Execute();
}
// Some sample implementations of IAction.
public sealed class ReadAction: IAction
{
public void Execute()
{
Console.WriteLine("ReadAction");
}
}
public sealed class ReadWriteAction: IAction
{
public void Execute()
{
Console.WriteLine("ReadWriteAction");
}
}
public sealed class GenericAction: IAction
{
public void Execute()
{
Console.WriteLine("GenericAction");
}
}
// The base ITest interface. 'out T' makes it covariant on T.
public interface ITest<out T> where T: IAction
{
IEnumerable<T> Actions
{
get;
}
}
// A ReadWriteTest class.
public sealed class ReadWriteTest: ITest<ReadWriteAction>
{
public ReadWriteTest(IEnumerable<ReadWriteAction> actions)
{
_actions = actions;
}
public IEnumerable<ReadWriteAction> Actions
{
get
{
return _actions;
}
}
private readonly IEnumerable<ReadWriteAction> _actions;
}
// A ReadTest class.
public sealed class ReadTest: ITest<ReadAction>
{
public ReadTest(IEnumerable<ReadAction> actions)
{
_actions = actions;
}
public IEnumerable<ReadAction> Actions
{
get
{
return _actions;
}
}
private readonly IEnumerable<ReadAction> _actions;
}
// A GenericTest class.
public sealed class GenericTest: ITest<IAction>
{
public GenericTest(IEnumerable<IAction> actions)
{
_actions = actions;
}
public IEnumerable<IAction> Actions
{
get
{
return _actions;
}
}
private readonly IEnumerable<IAction> _actions;
}
internal class Program
{
private static void Main()
{
// This demonstrates that we can pass the various concrete classes which have
// different IAction types to a single test method which has a parameter of
// type ITest<IAction>.
var readActions = new[]
{
new ReadAction(),
new ReadAction()
};
var test1 = new ReadTest(readActions);
test(test1);
var readWriteActions = new[]
{
new ReadWriteAction(),
new ReadWriteAction(),
new ReadWriteAction()
};
var test2 = new ReadWriteTest(readWriteActions);
test(test2);
var genericActions = new[]
{
new GenericAction(),
new GenericAction(),
new GenericAction(),
new GenericAction()
};
var test3 = new GenericTest(genericActions);
test(test3);
}
// A generic test method.
private static void test(ITest<IAction> data)
{
foreach (var action in data.Actions)
{
action.Execute();
}
}
}
}
If you want to be able to set the actions after creating the objects, you can add to each concrete class a setter method.
For example, you could change the ReadWriteTest class to:
public sealed class ReadWriteTest: ITest<ReadWriteAction>
{
public void SetActions(IEnumerable<ReadWriteAction> actions)
{
_actions = actions;
}
public IEnumerable<ReadWriteAction> Actions
{
get
{
return _actions;
}
}
private IEnumerable<ReadWriteAction> _actions = Enumerable.Empty<ReadWriteAction>();
}
In my app, I have deal with several different "parameters", which derive from IParameter interface, and also ParamBase abstract base class. I currently have two different parameter types, call them FooParameter and BarParameter, which both derive from ParamBase. Obviously, I can treat them both as IParameters when I need to deal with them generically, or detect their specific type when I need to handle their specific functionality.
My question lies in specific FooParameters. I currently have a few specific ones with their own classes which derive from FooParameter, we'll call them FP12, FP13, FP14, etc. These all have certain characteristics, which make me treat them differently in the UI. (Most have names associated with the individual bits, or ranges of bits). Note that these specific, derived FP's have no additional data associated with them, only properties (which refer to the same data in different ways) or methods.
Now, I'd like to keep all of these parameters in a Dictionary<String, IParameter> for easy generic access. The problem is, if I want to refer to a specific one with the special GUI functions, I can't write:
FP12 fp12 = (FP12)paramList["FP12"] because you can't downcast to a derived type (rightfully so). But in my case, I didn't add any data, so the cast would theoretically work.
What type of programming model should I be using instead? Thanks!
There's nothing really wrong with this approach, except for maybe storing the parameters in a dictionary. What is the purpose of doing that? Especially if you key them on their class name.
I would just use a List<IParameter> and have a control go through the collection and pick the right subclass out of there.
m_Parameters = new List<IParameter>();
//This control needs FP12
foreach(var param in Parameters) {
var fp12 = param as FP12;
if (fp12 != null) {
//do something with the param.
break;
}
}
After writing the above I think I finally understand what you are trying to do. If you want to perform an operation that is available on FP12 on any subclass of FooParameter then you need to take that operation out of FooParameter altogether. Since your parameter is data and that data is the same across different subclasses of FooParameter, it makes sense to only have one implementation of FooParameter ("data" class) and multiple "operation" classes.
//The one implementation of IParameter for all FooParameters
public class FooParameter : IParameter {
string Data1 {get;set;}
}
//base class for Foo Operation, only stores FooParameter
public class FooOperationBase {
protected readonly FooParameter m_Param;
public FooOperationBase (FooParameter param) {
m_Param = param;
}
}
//specific operations on FooParameter go in this class
public class FooOperation12 : FooOperationBase {
public FooOperation12(FooParameter param) : base(param) {}
public void DoSomeOperation() {
return m_Param.Data1 + " transformed";
}
}
If paramList["FP12"] is a FP12, that cast will work. Of course, if it's not it will throw a InvalidCastException. You could also use as, if you're not sure what type the object will be.
Whether this is an ideal design is a separate issue. Ideally, you want to prefer polymorphism, meaning the subclass of FooParameter knows to use its new special functions internally, and the outside code doesn't have to cast, or use as or is.
I'm not 100% sure where you're coming from with this question, but you could do something like this:
class Program
{
static void Main(string[] args)
{
var paramList = new List<IParameter>();
paramList.Add(new FooParameter());
paramList.Add(new BarParameter());
paramList.Add(new F1());
paramList.Add(new F2());
foreach (var p in paramList)
{
p.DoCommonOperation();
DoSpecificOperation(p);
}
Console.ReadKey();
}
private static void DoSpecificOperation(IParameter p)
{
if (p is F1)
{
(p as F1).F1Method();
}
else if (p is F2)
{
(p as F2).F2Method();
}
}
interface IParameter
{
void DoCommonOperation();
}
abstract class ParamBase : IParameter
{
public virtual void DoCommonOperation()
{
Console.WriteLine("ParamBase");
}
}
class FooParameter : ParamBase
{
public override void DoCommonOperation()
{
Console.WriteLine("FooParameter");
}
}
class BarParameter : ParamBase
{
public override void DoCommonOperation()
{
Console.WriteLine("BarParameter");
}
}
class F1 : FooParameter
{
public override void DoCommonOperation()
{
Console.WriteLine("F1");
}
public void F1Method()
{
Console.WriteLine("F1.F1Method");
}
}
class F2 : FooParameter
{
public override void DoCommonOperation()
{
Console.WriteLine("F2");
}
public void F2Method()
{
Console.WriteLine("F2.F2Method");
}
}
}
Essentially you have a method in the class that controls the list of IParameter objects that knows how to call the specific implementations, and uses is/as to do so.
Just for sanity's sake, why not use Dictionary<Type, IParameter>? With a little generics, you could do this:
public interface IParameter { }
public class FP12 : IParameter { public string fieldFP12 { get; set; } }
public class FP11 : IParameter { public string fieldFP11 { get; set; } }
public static class DictionaryHelper
{
public static T GetParameter<T>(this Dictionary<System.Type,
IParameter> target) where T : IParameter
{
return (T)target[typeof(T)];
}
}
Sample program and output:
class Program
{
static void Main()
{
Dictionary<Type, IParameter> parameters =
new Dictionary<Type, IParameter>();
parameters.Add(typeof(FP12), new FP12 { fieldFP12 = "This is FP12" });
parameters.Add(typeof(FP11), new FP11 { fieldFP11 = "This is FP11"});
// THIS IS WHERE YOU GET THE IPARAMETER YOU WANT - THE GENERICS WAY...
var fp12 = parameters.GetParameter<FP12>();
var fp11 = parameters.GetParameter<FP11>();
Console.WriteLine(fp12.fieldFP12);
Console.WriteLine(fp11.fieldFP11);
Console.ReadLine();
}
}
The resulting output:
This is FP12
This is FP11