Casting to run-time type - c#

Here is my structure :
Abstract Class - Action
--Abstract Class - ConfigsAction
---- ResetAction
---- SetToZeroAction
--Abstract Class - SettingsAction
---- EditLanguageAction
---- ChangeColorPrefAction
ManagerAccessPoint.Receive(Action action)
ManagerAccesPoint receives the action and ''sends'' it to the proper ConcreteManager.
So ManagerAccessPoint needs to Cast it either to ConfigsAction or SettingsAction
And ConfigManager/SettingsManager would then cast it to the proper action class would it be ResetAction, SetToZeroAction, EditLanguageAction or ChangeColorPrefAction.
I know i can save the action type with
Object.getType().name
as a string.
I know I can get the type back from the string with
Type­.GetType(string)
But how do I cast it back to that type ? It could be visualized as if it was this :
Retrievetype derievedAction = (RetrieveType)myAction
Where retrieveType is a Type variable
I found other ''similar'' question but none were giving me a working solution for my situation.
I actually need to be able to call Child's classe specific function once I received teh action at the right level, so that the behaviour is different for every child class.

What you're asking doesn't make sense. A cast is useful only if the type you're casting to is known statically at compile time, otherwise how would you do anything with it?

In short, you can't. You could use the 'dynamic' object which would allow you write code as if it had been cast, but I don't think that would be appropriate here.
Instead, you could try something like:
class ManagerAccessPoint
{
private ConfigManager _configManager;
private SettingsManager _settingsManager;
void Receive(Action action)
{
var configs = action as ConfigsAction;
if (configs != null)
{
_configManager.Receive(configs);
return;
}
var settings = action as SettingsAction;
if (settings != null)
{
_settingsManager.Receive(settings);
return;
}
}
}
class ConfigManager
{
void Receive(ConfigsAction action)
{
// repeat the same pattern here
var setToZero = action as SetToZeroAction;
if (setToZero != null)
{
// we have a setToZero action!
}
etc...
}
}

The class structure looks fine , and the concept of manager is also fine . But if you need to call a specific functionality of child class then we are losing/going away from the Abstraction concept.
Try to handle these via virtual/abstract contract methods.
For eg:
class ManagerAccessPoint
{
public void Receive (Action action)
{
//where CallContractMethod is an abstract/virtual method
//which serves as a contract and now via run time polymorphism
//the appropriate action method will be called.
//Each and every child class will have different behavior of this action.
action.CallContractMethod();
}
}

Related

calling static methods on a class after discovering that it supports it

This question was going to be "defining static interfaces' but I realized that was
already asked (answer from Skeet = No)
presupposed the answer
So the question is. I have a method that accepts a type (its not a generic method at the moment but could be changed if needed). I need to know if this type has a given method and if so call that method.
I know I could define an interface and make the class implement that interface and instantiate if its of the right type and call the method. Like this
public interface IDoFizz
{
void Fizz();
}
...
var t = Activator.CreateInstance(type);
if(t is IDoFizz)
{
(t as IDoFizz).Fizz();
}
the problem is that means I have to instantiate the object. This might be expensive, or even impossible (if it has no null contructor or its a static class)
So any ideas? I was thinking about something like
DoThing<T>(xxx) where T: IDoFizz
{
// code that calls IFoo.Fizz
}
DoThing<T>()
{
}
but it feels a bit clunky. Or I suppose I could use reflection to see if it supports the method.
"Can you describe the reasoning some more"
This is a job scheduling system. The type is the type of the job being submitted. The jobs all implement IAmAJob. Once the job gets run it is instantiated and IAmAJob.run is invoked. SO obviously I could add the Fizz (actually a preflight check) to IAmAJob interface. But that means I have to instantiate it - which I dont want to do. The preflight check is a perfectly happy being a static method
If you need to call a non static member (like in your examples, but unlike your question title) you can do:
DoThing<T>() where T: IDoFizz, new()
{
new T().Fizz();
}
But for static method you would have to use reflection like:
public void DoThing(Type t)
{
var m = t.GetMethod("Fizz", BindingFlags.Public | BindingFlags.Static);
if(m != null)
m.Invoke(null, null);
}

Lazy<T> and reflection-based initalization

I have a series of classes which initialize themselves when created based on using reflection to read a custom attribute on each property/field. The logic for all that is contained in an Initialize() method which they all call, which exists on the base class they inherit from.
I want to add usages of Lazy<T> to these classes, but I don't want to specify the function(s) in the constructor for each class, because they are "thin" constructors and the heavy lifting is in Initialize(). Conversely, I want to keep type-safety and such so I can't just provide a string of the code to use to initialize the Lazy<T>. The problem is that any usage which refers to the specific properties of the object can't be used in a static context.
Specifically, this is what I want my code to look like in an ideal world:
public class Data : Base
{
public Data(int ID) { Initalize(ID); }
[DataAttr("catId")] // This tells reflection how to initialize this field.
private int categoryID;
[LazyDataAttr((Data d) => new Category(d.categoryID))] // This would tell reflection how to create the Lazy<T> signature
private Lazy<Category> _category;
public Category Category { get { return _category.Value; } }
}
public abstract class Base
{
protected void Initalize(int ID)
{
// Use reflection to look up `ID` and populate all the fields correctly.
// This is where `categoryID` gets its initial value.
// *** This is where _category should be assigned the correct function to use ***
}
}
I would then access this the same way I would if Category were an automatic property (or an explicitly lazy loaded one with an _category == null check)
var data = new Data();
var cat = data.Category;
Is there any way I can pass the type information so that the compiler can check that new category(d.categoryID) is a valid function? It doesn't have to be via an Attribute, but it needs to be something I can see via Reflection and plug in to anything that has a Lazy<T> signature.
As an alternative, I will accept a way to do
private Lazy<Category> _category = (Data d) => new Category(d.categoryID);
This could either avoid reflection altogether, or use it to transform from this form to a form that Lazy<T> can handle.
I ended up using a solution inspired by #Servy's suggestion to get this working. The base class's Initialize() method now ends with:
protected void Initialize()
{
// Rest of code...
InitializeLazyVars();
/* We need do nothing here because instantiating the class object already set up default values. */
foreach (var fi in GetLazyFields())
{
if (fi.GetValue(this) == null)
throw new NotImplementedException("No initialization found for Lazy<T> " + fi.Name + " in class " + this.GetType());
}
}
InitializeLazyVars() is a virtual method that does nothing in the base class, but will need to be overridden in the child classes. If someone introduces a new Lazy<T> and doesn't add it to that method, we'll generate an exception any time we try to initialize the class, which means we'll catch it quickly. And there's only one place they need to be added, no matter how many constructors there are.

How to get Type name of a CallerMember

I got this class
public class fooBase
{
public List<MethodsWithCustAttribute> MethodsList;
public bool fooMethod([CallerMemberName]string membername =""))
{
//This returns a value depending of type and method
}
public void GetMethods()
{
// Here populate MethodsList using reflection
}
}
And This Attribue Class
// This attribute get from a database some things, then fooMethod check this attribute members
public class CustomAttribute
{
public string fullMethodPath;
public bool someThing ;
public bool CustomAttribute([CallerMemberName]string membername ="")
{
fullMethodPath = **DerivedType** + membername
// I need here to get the type of membername parent.
// Here I want to get CustClass, not fooBase
}
}
Then I have this
public class CustClass : fooBase
{
[CustomAttribute()]
public string method1()
{
if (fooMethod())
{
....
}
}
}
I need the Type name of the CallerMember, there is something like [CallerMemberName] to get the Type of class owner of the Caller ?
It isn't foolproof, but the convention with .NET is to have one type per file and to name the file the same as the type. Our tooling also tends to enforces this convention i.e. Resharper & Visual Studio.
Therefore it should be reasonable to infer the type name from the file path.
public class MyClass
{
public void MyMethod([CallerFilePath]string callerFilePath = null, [CallerMemberName]string callerMemberName = null)
{
var callerTypeName = Path.GetFileNameWithoutExtension(callerFilePath);
Console.WriteLine(callerTypeName);
Console.WriteLine(callerMemberName);
}
}
Caller member
Granted, getting the caller member name is not "natural" in the object model.
That's why the C# engineers introduced CallerMemberName in the compiler.
The real enemy is duplication, and stack-based workarounds are inefficient.
[CallerMemberName] allows to get the information without duplication and without ill-effect.
Caller type
But getting the caller member type is natural and easy to get without duplication.
How to do it
Add a "caller" parameter to fooMethod, no special attribute needed.
public bool fooMethod(object caller, [CallerMemberName]string membername = "")
{
Type callerType = caller.GetType();
//This returns a value depending of type and method
return true;
}
And call it like this:
fooMethod(this);
This answer the question
You stated
// Here I want to get CustClass, not fooBase
and that's exactly what you'll get.
Other situations where it would not work, with solutions.
While this exactly answers your requirements, there are other, different, cases where it wouldn't work.
Case 1: When caller is a static methods (there is no "this").
Case 2: When one wants the type of the caller method itself, and not the type of the caller itself (which may be a subclass of the first).
In those cases, a [CallerMemberType] might make sense, but there are simpler solutions.
Notice that the static caller case is simpler: there is no object so no discrepancy between it and the type of the calling method. No fooBase, only CustClass.
Case 1: When caller is a static methods (there is no "this")
If at least one caller is a static method, then don't do the GetType() inside the method but on call site, so don't pass "this" to the method but the type:
public bool fooMethodForStaticCaller(Type callerType, [CallerMemberName]string membername = "")
Static caller will do:
public class MyClassWithAStaticMethod // can be CustClass, too
{
public static string method1static()
{
fooMethodForStaticCaller(typeof(MyClassWithAStaticMethod));
}
}
To keep compatibility with object callers, either keep the other fooMethod that takes the this pointer, or you can remove it and object callers will do:
fooMethod(this.GetType());
You can notice that the typeof(MyClassWithAStaticMethod) above repeats the class name and it's true. It would be nicer to not repeat the class name, but it's not such a big deal because this repeats only once, as a typed item (not a string) and inside the same class. It's not as serious a problem as the original problem that the [CallerMemberName] solves, which was a problem of repeating the caller name in all call sites.
Case 2: When one wants the type of the caller method, not the type of the caller
For example, in class fooBase you want to call anotherFooMethod from object context but want the type being passed to always be fooBase, not the actual type of the object (e.g. CustClass).
In this case there is a this pointer but you don't want to use it. So, just use actually the same solution:
public class fooBase
{
[CustomAttribute()]
public string method1()
{
if (anotherFooMethod(typeof(fooBase)))
{
....
}
}
}
Just like in case 1, there is one repetition, not one per call site, unless you have an pre-existing problem of rampant code duplication, in which case the problem being addressed here is not the one you should worry about.
Conclusion
[CallerMemberType] might still make sense to avoid duplication at all, but:
anything added to the compiler is a complexity burden with maintenance cost
given the existing solutions I'm not surprised there are items with higher priority in the C# development team list.
See Edit 2 for the better solution.
The information that CompilerServices provides is too little in my opinion to get the type from the calling method.
What you could do is use StackTrace (see) to find the calling method (using GetMethod()) and get the type using Reflection from there.
Consider the following:
using System.Runtime.CompilerServices;
public class Foo {
public void Main() {
what();
}
public void what() {
Bar.GetCallersType();
}
public static class Bar {
[MethodImpl(MethodImplOptions.NoInlining)] //This will prevent inlining by the complier.
public static void GetCallersType() {
StackTrace stackTrace = new StackTrace(1, false); //Captures 1 frame, false for not collecting information about the file
var type = stackTrace.GetFrame(1).GetMethod().DeclaringType;
//this will provide you typeof(Foo);
}
}
}
Notice - As #Jay said in the comments, it might be pretty expensive but it does the work well.
Edit:
I found couple of arcticles comparing the performance, and it is indeed horrbily expensive comparing to Reflection which is also considered not the best. See: [1] [2]
Edit 2:
So after a look in depth on StackTrace, it is indeed not safe to use it and even expensive.
Since every method that will be called is going to be marked with a [CustomAttribute()], it is possible to collect all methods that contains it in a static list.
public class CustomAttribute : Attribute {
public static List<MethodInfo> MethodsList = new List<MethodInfo>();
static CustomAttribute() {
var methods = Assembly.GetExecutingAssembly() //Use .GetCallingAssembly() if this method is in a library, or even both
.GetTypes()
.SelectMany(t => t.GetMethods())
.Where(m => m.GetCustomAttributes(typeof(CustomAttribute), false).Length > 0)
.ToList();
MethodsList = methods;
}
public string fullMethodPath;
public bool someThing;
public CustomAttribute([CallerMemberName] string membername = "") {
var method = MethodsList.FirstOrDefault(m=>m.Name == membername);
if (method == null || method.DeclaringType == null) return; //Not suppose to happen, but safety comes first
fullMethodPath = method.DeclaringType.Name + membername; //Work it around any way you want it
// I need here to get the type of membername parent.
// Here I want to get CustClass, not fooBase
}
}
Play around with this approach to fit your precise need.
Why not just use public void MyMethod<T>(params) { string myName = typeof(T).Name }
then call it Logger.MyMethod<Form1>(...);
You avoid the performance hit of reflection, if you just need basic info.

How do I return a C# web service that has a generic property?

I am creating a web service, and want to be a bit more elegant with the return data, instead of having lots of properties that the consumer needs to check.
Depending on what data is generated behind the scenes, I need to be able to return error data, or the data the consumer was expecting.
Instead of having a large flat object, and filling the properties when needed, and letting the user check a 'success' flag, I'd like a single property, Data, to be either an instance of an error class, or an instance of a success class.
This is kind of what I want to do:
class ItemResponse
{
public bool Success { get; set; }
public T Data{ get; set; }
}
if( /*acceptance criteria*/ )
{
ItemResponse<SuccessData> resp = new ItemResponse<SuccessData>();
resp.Data = new SuccessData();
}
else
{
ItemResponse<ErrorData> resp = new ItemResponse<ErrorData>();
resp.Data = new ErrorData();
}
return resp;
public class SuccessData
{
}
public class ErrorData
{
}
Then have the web method return the object, with the generic property.
Is this possible, and if so, how would I do it, given that the webmethod return type has to be typed correctly?
Generics are a tool for adding type safety during compile time. Consequently, the concrete type used by the consumer of the class must be known at compile time. If you create a function
List<T> myFunction<T>() {...}
...then you need to specify T when calling it, e.g.
var myResult = myFunction<int>();
...which makes the concrete type known at compile time. (Even if you don't specify T because it can be infered, the concrete type is also known at compile time.)
You, however, want the generic type of Data to be determined at run-time: If an error occured, you return an ItemResponse<SuccessData>, otherwise an ItemResponse<ErrorData>. That's just not how generics work.
Short version, you can't do what you're suggesting as you've laid it out.
Long(er) version Part A:
A web service can be considered like a class' method, and actually is a method off of your web service class. I would recommend going over some web service tutorials in order to get a better grasp of the mechanics behind setting up a web service. MSDN has a number of Microsoft stack specific tutorials that are easily found with your favorite search engine.
The return object off of a method is not allowed to have polymorphic behavior, which is essentially what your asking for.
This pseudo code is equivalent to what you're trying to create and that's why the compiler isn't allowing it. It doesn't know which DoSomething() you're attempting to call.
class myFoo
{
public SuccessResponse DoSomething() {....}
public ErrorResponse DoSomething() {....}
}
Alternatively, you could envisage something like this:
public [SuccessResponse | ErrorResponse] DoSomething()
but that fails for what should be obvious reasons as well. C# simply doesn't support polymorphic returns.
Part B
Even if we focus on just resp.Data, that object still has to be declared as some sort of type.
class Response
{
public Collection<someType> Data;
}
If your SuccessData and ErrorData implement the same interface then someType could simply be IyourInterface but that raises another issue. Namely, how will the end user know whether they were given good data in Data or whether there is an error response tucked in there instead.
WCF, I believe, will be nice enough to serialize IyourInterface for you so long as you declare it as a public part of the WCF service object. But that still doesn't resolve how your end user will know what to do.
If you're willing for a little less elegance in the response, a classic pattern is to simply bundle your success data and error objects together into another response class like this:
class myResponse
{
public SuccessResponse myRespData;
public ErrorResponse myError
}
Now, the end user checks to see if there's an error if they care. Presuming no error, then they go and look into the response data.
Based upon your comment, yes, you can do the following too:
class Response
{
public List<IYourData> Data;
public YourEnum ReturnType;
}
public class ResponseData : IYourData { ... }
public class ErrorData : IYourData { ... }
And then on the client, you can perform a simple check like this:
if( ReturnType == YourEnum.Success ) { ... }
else if( ReturnType == YourEnum.Error ) { ... }
else ...
WCF will handle the serialization of List for you. It'll either convert to an array or pass the collection directly depending upon what settings you have in place. There are some SO Q&A's that handle that particular aspect.

C# What is the best way to determine the type of an inherited interface class?

In my application I work with criterias. I have one base Criteria interface and and other interfaces who inherits from this base interface:
ICriteria
|
|
----------------------
| |
ITextCriteria IChoices
What I'd like to know is, what is the best way to know what Type the class is?
In my code I have a dropdown box and based on that I have to determine the type:
// Get selected criteria
var selectedCriteria = cmbType.SelectedItem as ICriteria;
if (selectedCriteria is IChoices)
{
//selectedCriteria = cmbType.SelectedItem as IChoices; Doesn't work
IChoices criteria = selectedCriteria as IChoices;//cmbType.SelectedItem as IChoices;
SaveMultipleChoiceValues(criteria);
//_category.AddCriteria(criteria);
}
else
{
//ICriteria criteria = selectedCriteria; //cmbType.SelectedItem as ICriteria;
if (selectedCriteria.GetCriteriaType() == CriteriaTypes.None)
{
return;
}
//_category.AddCriteria(criteria);
}
_category.AddCriteria(selectedCriteria);
selectedCriteria.LabelText = txtLabeltext.Text;
this.Close();
My question is, is this the best way? Or is there a better way to achieve this?
The chance is big that there are coming more interfaces based on ICriteria.
EDIT:
I have 2 types of controls which I want to add dynamically to my application. One control is a textbox and the other is a radio button.
For a radio button the user can define the options. When the options are defined, the user must choose one of the options and the chosen option must be saved in the database (this is later used to perform search operations). So, when the Save button is clicked, I have to determine the chosen type (radio or text) and save the answer possibilities (if it is a radio).
For a textbox, this doesn't have any answer possibilities. For that reason it has a different interface.
I hope I make it a little bit clearer now. Here is another question which is related: C# How to implement interface where concrete classes differs?
EDIT II:
This is how my method SaveMultipleChoiceValues looks like:
private void SaveMultipleChoiceValues(IChoices criteria)
{
foreach (DataGridViewRow row in dgvCriteriaControls.Rows)
{
if (row == dgvCriteriaControls.Rows[dgvCriteriaControls.Rows.Count - 1])
continue;
//multipleChoice.AddChoice(row.Cells["Name"].Value.ToString());
string choice = row.Cells["Name"].Value.ToString();
criteria.AddChoice(choice);
}
}
This looks like a prime example for polymorphism.
Instead of trying to do a type switch on your ICriteria implementation, why don't you add a method to ICriteria (or possibly a virtual method to some common base class of all ICriteria implementations), and just call that?
Obviously the implementation of this method would need access to objects that do not belong in your ICriteria instances, but that is a problem you can solve using other design patterns according to the specifics of your scenario.
Update:
Here's a complete solution, incorporating the code you posted:
Create a new interface ICriteriaView which models the view (in your case a Form) where ICriteria are displayed. The form needs to do some processing depending on the exact interface that criteria implement, so add a method with one overload for each interface that exists in your code. Do not add an overload for ICriteria itself. [1]
interface ICriteriaView {
void ProcessCriteria(IChoices criteria);
void ProcessCriteria(ITextCriteria criteria);
}
Your form will implement this interface, providing methods where suitable processing for each subtype of ICriteria will occur:
class MyForm : ICriteriaView {
public void ProcessCriteria(IChoices criteria) {
this.SaveMultipleChoiceValues(criteria);
}
public void ProcessCriteria(ITextCriteria criteria) {
// do nothing
}
private void SaveMultipleChoiceValues(IChoices criteria)
{
foreach (DataGridViewRow row in dgvCriteriaControls.Rows)
{
if (row == dgvCriteriaControls.Rows[dgvCriteriaControls.Rows.Count - 1])
continue;
//multipleChoice.AddChoice(row.Cells["Name"].Value.ToString());
string choice = row.Cells["Name"].Value.ToString();
criteria.AddChoice(choice);
}
}
}
Each implementation of ICriteria will need to implement a method which calls the appropriate ICriteriaView overload for its type. This is where the "redirection magic" happens: we will use polymorphism to get the compiler to "discover" the actual type of ICriteria our object is, and then use method overloading on ICriteriaView.ProcessCriteria to access the appropriate code.
interface ICriteria {
void PerformProcessingOn(ICriteriaView view);
}
interface IChoices : ICriteria {
}
interface ITextCriteria : ICriteria {
}
And this is where the dispatch to the appropriate overload happens:
class MultipleChoice : IChoices {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
class SimpleInput : ITextCriteria {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
Then, your code would do:
// Get selected criteria
var selectedCriteria = cmbType.SelectedItem as ICriteria;
// Here's where polymorphism kicks in
selectedCriteria.PerformProcessingOn(this);
// Finally, code that runs the same for all objects
_category.AddCriteria(selectedCriteria);
selectedCriteria.LabelText = txtLabeltext.Text;
this.Close();
Maintenance:
Whenever you add a new ICriteria sub-interface implementation, the definition of ICriteria will force you to implement the PerformProcessingOn method on it. Inside that method, all you can do really is call view.ProcessCriteria(this). In turn, this will force you to implement an appropriate ProcessCriteria overload in ICriteriaView and MyForm.
As a result, we have achieved two important objectives:
The compiler will not allow you to add a new ICriteria implementation without specifying exactly how that implementation should interact with ICriteriaView.
It is easy to discover from source code exactly what MyView does with e.g. IChoices when reading the code for MultipleChoice. The structure of the code leads you to MyForm.SaveMultipleChoiceValues "automatically".
Notes:
[1] The choice of adding an overload for ICriteria itself or not is really a tradeoff:
If you do add one, then code like this:
class MultipleChoice : IChoices {
public PerformProcessingOn(ICriteriaView view) {
view.ProcessCriteria(this);
}
}
will compile successfully always, because even if there is no ICriteriaView.ProcessCriteria(IChoices) overload there will still be the ICriteriaView.ProcessCriteria(ICriteria) overload that the compiler can use.
This means that, when adding a new ICriteria sub-interface implementation, the compiler will no longer force you to go check if the implementation of ICriteriaView.ProcessCriteria(ICriteria) really does the right thing for your new implementation.
If you do not add one, then the moment you write view.ProcessCriteria(this); the compiler will force you to go check (and update) ICriteriaView and MyForm accordingly.
In this scenario, and with the information you have provided, I believe that the appropriate choice would be the last one.
[2] As you can see above, the implementation of ICriteria.PerformProcessingOn inside MultipleChoice and SimpleInput looks exactly the same. If these two classes have a common base (which is quite possible in practice), you might be tempted to move the "duplicated" code into that base. Do not do that; it will cause the solution to break.
The tricky part is that inside MultipleChoice, when you do view.ProcessCriteria(this); the compiler can infer that the static type of this is IChoices -- this is where the redirection happens! If you move the call to ProcessCriteria inside a hypothetical base class CriteriaBase : ICriteria, then the type of this will become ICriteria and the dispatch of the call to the appropriate ICriteriaView.ProcessCriteria overload will no longer work.
You could do this:
var selectedCriteria = cmbType.SelectedItem as ICriteria;
if (typeof(IChoices).IsAssignableFrom(selectedCriteria.GetType()))
{
IChoices criteria = selectedCriteria as IChoices;
SaveMultipleChoiceValues(criteria);
}
else if(typeof(ITextCriteria).IsAssignableFrom(selectedCriteria.GetType()))
{
if (selectedCriteria.GetCriteriaType() == CriteriaTypes.None)
{
return;
}
}
But polymorphism is probably your best bet.
That is not the best way. If you are performing different actions based on the type of an object, you should probably be using polymorphism instead for a myriad number of reasons.
How you use polymorphism depends on what you actually need to have done based on the different types of ICriteria that are being used. If you just need to get a string containing all of their members, you could easily add a method to ICriteria and hand the responsibility to the class itself instead of the code that depends on it. This reduces duplication, puts code in a logical place, and makes sure you don't forget to add code for a new type of ICriteria.
If you give us more information on how you want different types to be treated/behave, we can probably give you more specific advice. :D
Here is a long term solution to an ever expanding list of critera without having to add more if/then/else.
While this code is complex to someone not used to designing in this manner, it allows you to keep your method dealing with criteria the same, and just register new delegates to handle additional criteria.
The idea is to create a map of Type objects that hold delegates in which to execute. You can then register new delegates to execute based on new Types as you generate them.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Stackoverflow_4527626
{
delegate void CriteraDelegate(params object[] args);
class CriteraManager
{
private Dictionary<Type, CriteraDelegate> criterian = new Dictionary<Type, CriteraDelegate>();
public void RegisterCritera(Type type, CriteraDelegate del)
{
criterian[type] = del;
}
public void Execute(Object criteria, params object[] args)
{
Type type = criteria.GetType();
/// Check to see if the specific type
/// is in the list.
if (criterian.ContainsKey(type))
{
criterian[type](args);
}
/// If it isn't perform a more exhaustive search for
/// any sub types.
else
{
foreach (Type keyType in criterian.Keys)
{
if (keyType.IsAssignableFrom(type))
{
criterian[keyType](args);
return;
}
}
throw new ArgumentException("A delegate for Type " + type + " does not exist.");
}
}
}
interface InterfaceA { }
interface InterfaceB1 : InterfaceA { }
interface InterfaceB2 : InterfaceA { }
interface InterfaceC { }
class ClassB1 : InterfaceB1 { }
class ClassB2 : InterfaceB2 { }
class ClassC : InterfaceC { }
class Program
{
static void ExecuteCritera1(params object[] args)
{
Console.WriteLine("ExecuteCritera1:");
foreach (object arg in args)
Console.WriteLine(arg);
}
static void ExecuteCritera2(params object[] args)
{
Console.WriteLine("ExecuteCritera2:");
foreach (object arg in args)
Console.WriteLine(arg);
}
static void Main(string[] args)
{
CriteraDelegate exampleDelegate1 = new CriteraDelegate(ExecuteCritera1);
CriteraDelegate exampleDelegate2 = new CriteraDelegate(ExecuteCritera2);
CriteraManager manager = new CriteraManager();
manager.RegisterCritera(typeof(InterfaceB1), exampleDelegate2);
manager.RegisterCritera(typeof(InterfaceB2), exampleDelegate2);
manager.RegisterCritera(typeof(InterfaceC), exampleDelegate1);
ClassB1 b1 = new ClassB1();
ClassB2 b2 = new ClassB2();
ClassC c = new ClassC();
manager.Execute(b1, "Should execute delegate 2");
manager.Execute(b2, "Should execute delegate 2");
manager.Execute(c, "Should execute delegate 1");
}
}
}

Categories

Resources