Why I can add method with default argument to event Action? - c#

Consider class
class FirstClass
{
//Some fields, ctors and methods
...
public event Action Test
{
add
{
var method = value.Method;
var parameters = method.GetParameters (); //Count == 1
// (1)
//I don't know anything about value so I think I can pass null as argument list because it's Action, not Action<T>
//And we get Reflection.TargetParameterCountException here.
method.Invoke (value.Target, null);
//Instead of calling Invoke as done above, we should call it like that:
// (2)
method.Invoke (value.Target, new object[] { null });
//But since it's Action, we should be able to call it with (1) not with (2)
}
remove
{
...
}
}
}
And another class
class SecondClass
{
public void TestMethod (Action action = null)
{
...
}
public void OtherMethod ()
{
var a = new FirstClass ();
a.Test += TestMethod;
}
}
IMHO: adding method with default arguments to delegate without parameters shouldn't be allowed at type system level.
Why it is allowed?
P.S. You could do this not only in add { } accessor but in any other place, code above is just example.

This should not compile.
Delegate Action has a signate of zero parameters, and no return value:
public delegate void Action();
So only methods with zero parameters and not return values can be assigned to it. Your second class SecondClass.TestMethod does have an argument of type Action (to make it all confusing, I guess ;)). So that method would be compatible with another Action delegate (where T = Action):
public delegate void Action<T>();
If you even do try to manage to call FirstClass.Test.Add, and you try to make the two Invoke-calls, the first one should fail.
Why? The method is a MethodInfo of SecondClass.TestMethod. This method requires at least one parameter. This parameter must be inside the object-array given to the invoke method. But, in your first call, you do not have an object-array; your object array is set to null. And an object-array set to null cannot hold anything, not even 0 elements, let alone 1 element having null.
The second Invoke does have an object-array with one element, having null.

Related

Delegate in parameter

I have a bunch of methods that return List of GridTiles, for example GetTopNeighbour. I would like to be able to pass them to method AutoConnect using the GetNeighboursHandler delegate as a parameter.
public delegate List<GridTile> GetNeighboursHandler(GridTile c);
public List<GridTile> GetTopNeighbour(GridTile c)
{
//do stuff and return list
return null;
}
public GridTile AutoConnect(GridTile c, GetNeighboursHandler del)
{
List<GridTile> tempList = del(c);
// do stuff with the tempList
}
public void Test(GridTile c)
{
AutoConnect(c, GetTopNeighbour(c));
}
In the Test method I get the error: ... cannot convert ...Generic.List...to GetNeighboursHandler.
Have I completely misunderstood how delegates work?
You need to pass a delegate (which is an object that knows how to call the method, ie: it holds the reference of a method)
What you have done is passing the function result that you get after it's execution
GetTopNeighbour(c) returns a List<GridTile>, and you are passing this return value in your code here
AutoConnect(c, GetTopNeighbour(c));
Instead you should pass the reference to that method GetTopNeighbour
AutoConnect(c, GetTopNeighbour);
Refer these This is a tutorial and here's another one
You have to pass the method (or rather, method group) itself, instead of calling it:
AutoConnect(c, GetTopNeighbour);
You're passing the result of GetTopNeighbour(c), which is a List<GridTile>, as a parameter to AutoConnect.
Instead, you want to pass the MethodGroup to be converted to a delegate, like so:
AutoConnect(c, GetTopNeighbour);

Why doesn't this method need a parameter?

I'm working with a project for thesis-work for a company and I'm having some difficulties understanding some code.
In their code they have a line like this
_subscriber.StartSubscribing(_messageHandler.HandleMessage);
where _subscriber is function is defined
public override void StartSubscribing(Action<QueueItem> messageHandlerMethod);
And _messageHandler is defined
public void HandleMessage(QueueItem message)
{
//Do code here
}
How come at the top the messageHandler don't need a parameter for HandleMessage?
E.I
_subscriber.StartSubscribing(_messageHandler.HandleMessage(QueueItem));
Because you're not actually executing the method HandleMessage (which would happen if you had parentheses and a parameter). You are passing it as a reference to StartSubscribing which expects a method with a specified signature (void return, one parameter of type QueueItem)
Action<T> is a generic delegate, this particular version is a delegate which specifies no return (void) and a single parameter of type T (or QueueItem in your example)
In fact, it is the method StartSubscribing (or perhaps the class it belongs to) which is likely to provide the instance of QueueItem - perhaps something like this:
public override void StartSubscribing(Action<QueueItem> messageHandlerMethod)
{
// do something to get/create a QueueItem
QueueItem item = SomeMagic();
// pass it back to the passed in delegate
messageHandlerMethod(item);
}
With _subscriber.StartSubscribing(_messageHandler.HandleMessage) you are using a more direct way for _subscriber.StartSubscribing(msg => _messageHandler.HandleMessage(msg)).
So it does need a parameter.

Create a delegate when the exact type of the argument is unknown

I have some troubles to create the right delegate for this instance method:
public T AddComponent<T>() where T : Component
{
....
}
I am using reflection to get the specific MethodInfo and on Delegate.CreateDelegate I am getting an error binding to target method
private delegate T AddComponent<out T>();
private static AddComponent<Component> AddC { get; set; }
public void Test()
{
var go = new GameObject();
var targetAddComponent =
typeof (GameObject).GetMethods().First(m => m.Name == "AddComponent" && m.GetParameters().Length == 0);
AddC = (AddComponent<Component>) Delegate.CreateDelegate(typeof (AddComponent<Component>), go, targetAddComponent, true);
....
}
Do you have any clues on what I am doing wrong?
The method info is a method info for method GameObject.AddComponent<T>, which returns T. The delegate, which you have incredibly confusingly named the same as the method, must be to a method that returns Component. What have you done to cause T to equal Component? Nothing.
Put another way: the method info is a method info to something that isn't actually a callable method until it is constructed. It's a generic pattern for making methods, not a method. Make it a method if you want to make a delegate to it. You need to supply a type argument for type parameter T in the method.

Invoking an Action - determine if the instance it belongs to is null

I have a method that takes an Action as a parameter. Actions are stored in a queue and executed when particular resources become available. Before I invoke an Action, I'd like to check if the instance it is a member of is null.
I did a simple test with the following stupid example. The Action invoked successfully after setting the invokee to null, and as expected, I got a NullReferenceException when attempting to access the property on the null invokee. Nothing jumped out at me when examining the Action at runtime that suggested I could determine if its instance was null.
I guess I could pass in the Action and the instance as parameters and test if the instance is null before invoking. Is it possible to test for a null invokee, or is this just a case of bad design on my part?
UPDATE:
I added the line,
if (explosion.Target != null)
to Bazooka.Fire(), to check for a null target, but it is still invoking the delegate in my example.
public void LetsDoThis()
{
var bazooka = new Bazooka();
var rocketLauncher = new RocketLauncher();
bazooka.LockAndLoad(rocketLauncher.BlowStuffUp);
rocketLauncher = null;
bazooka.Fire();
bool wasThisCompletelyAwesome = rocketLauncher.ThisIsAwesome;
}
public class RocketLauncher
{
public void BlowStuffUp()
{
bool stuffIsBlowingUp = true;
}
public bool ThisIsAwesome
{
get
{
return true;
}
}
}
public class Bazooka
{
private List<Action> explosions = new List<Action>();
public void LockAndLoad(Action loadIt)
{
this.explosions.Add(loadIt);
}
public void Fire()
{
foreach (Action explosion in explosions)
if (explosion.Target != null)
explosion.Invoke();
}
}
This won't work.
The Action does not in any way care about the original reference variable you got it from, it makes a copy of the reference value, and thus has its own reference.
Note that this also means that as long as you still have a reference to the delegate, even though you have no other references to the original object, it will still not be eligible for garbage collection.
The .Target property refers to the instance on which the method that the delegate refers to should be invoked, basically the this "parameter" to that method.
Thus, to have a null target you need to get the delegate from a static method, try this in LINQPad:
void Main()
{
Action a = Static.StaticMethod;
(a.Target == null).Dump();
}
public static class Static
{
public static void StaticMethod() { }
}
You can see that the delegate carries its own instance with this LINQPad code:
void Main()
{
Dummy d = new Dummy { Name = "A" };
Action a = d.Method;
d = new Dummy { Name = "B" };
Action b = d.Method;
d = null;
a();
b();
}
public class Dummy
{
public string Name { get; set; }
public void Method()
{
Debug.WriteLine("Name=" + Name);
}
}
The output here will be
Name=A
Name=B
As requested, let me clarify the difference between the instance, the reference, and the variable.
When you construct an object instance, like this:
var rocketLauncher = new RocketLauncher();
What you're doing is calling a method known as a constructor. The return value from this constructor is a reference to the newly constructed object. Basically, it's a pointer, meaning a memory address of where in the memory that object now lives. If it makes it easier to understand the rest of this answer you can consider it to be just a number.
Additionally you declared a variable, rocketLauncher, to hold this reference, this number.
Note that the object is separate from the variable, they're two distinct items. In one place in memory you have an object, in another place you have the variable containing the reference to that object, it's address, that number.
So when you do this:
bazooka.LockAndLoad(rocketLauncher.BlowStuffUp);
Let's simplify it a bit:
Action a = rocketLauncher.BlowStuffUp;
// bazooka.LockAndLoad(a);
let's forget about the part where we call that LockAndLoad method, and look at what happened when we "converted" the method BlowStuffUp into a delegate of type Action.
Basically, two things was "grabbed":
Which method to make the delegate refer to
The object instance on which to call that method
You can liken this to the following code:
MethodReference = rocketLauncher.BlowStuffUp;
object target = rocketLauncher;
// wrap this into a delegate
This now means you have two references to that object, one lives in the rocketLauncher variable, the other now lives inside the delegate.
What you do with that variable does not in any way change the value of that delegate, it still points to the same object as before. Basically it made a copy of that number. That number is still sitting there inside the delegate.
This is pretty much exactly the same as this:
int a = 10;
int b = a;
a = 0;
// b is still 10
So, to conclude, the .Target property of the delegate does not in any way know, or care, about the original variable that you got the delegate from. A copy was made of the reference value from that original variable, into the delegate, and what you do with the variable afterwards makes no difference at all.
So basically:
The instance is the object, it lives somewhere in memory
The reference is basically the address to it, and you can look at it as sort of a number
The variable is one place where you can store that reference
Now, what if you really want to make the delegate depend on the variable, and care about the value it now has, when you get around to calling it?
Well, one way would be to do this:
bazooka.LockAndLoad(delegate
{
if (rocketLauncher != null)
rocketLauncher.BlowStuffUp();
});
This would make an anonymous method, that would capture the variable itself, and then inside that anonymous method you could explicitly check what value the variable has at the time you call the delegate. If this part, about an anonymous method, does not make sense, you should ask another question here (ideally after reading a bit about anonymous methods, captured variables, and looked over some of the existing questions here on SO).
To test out an anonymous method, test the following code in LINQPad:
void Main()
{
object dummy = new object();
Action a = delegate
{
if (dummy != null)
Debug.WriteLine("not null");
else
Debug.WriteLine("null");
};
a();
dummy = null;
a();
}
It will print out:
not null
null
Use the Target property to check:
if(yourAction.Target != null) {
//...
}
Any Delegate type has a property called Target, so you can also use this for other types of delegate.
Update: In fact, when you use your Action to wrap some method of an object, that object won't never be disposed and that means the NullReferenceException can't be thrown in that case Unless you wrap another method of another object and this method has something to do with the null object.
Well, not in any way trying to argue with Lasse's rather detailed response, I would like to throw in my 5 cents on this.
When you invoke the LockAndLoad method of the bazooka class you simply add the method that's passed to the method to the List explosions collection of the bazooka class. Nulling the instantiation of the class whose method you had passed to the LockAndLoad method (in your example 'rocketLauncher') has NO effect on that collection, meaning that the Target property of the specific Action will not become null. You would have to explicitly remove the method from that collection BEFORE nulling the instantiation of the class.
bazooka.Unload(rocketLauncher.BlowStuffUp);
rocketLauncher = null;
Of course this works only if you modified your bazooka class to the following method in your bazooka class:
public void Unload(Action unloadIt)
{
if (explosions.Contains(unloadIt))
explosions.Remove(unloadIt);
}
This may not be what you are hoping for, but I hope it helped anyhow.

Better Alternative to Case Statement

I currently have a switch statement that runs around 300 odd lines. I know this is not as giant as it can get, but I'm sure there's a better way to handle this.
The switch statement takes an Enum that is used to determine certain properties that pertain to logging. Right now the problem sets in that it is very easy to leave out an enumeration value and that it will not be given a value as it is not in the switch statement.
Is there an option one can use to ensure that every enumeration is used and given a custom set of values it needs to do its job?
EDIT:
Code sample as requested: (This is simplistic, but shows exactly what I mean. Also an Enumeration would exist with the below values.)
internal void GenerateStatusLog(LogAction ActionToLog)
{
switch (ActionToLog)
{
case LogAction.None:
{
return;
}
case LogAction.LogThis:
{
ActionText = "Logging this Information";
LogText = "Go for it.";
break;
}
}
// .. Do everything else
}
EDIT
I thought this over again, looked around in related questions in SO, and I wrote some code. I created a class named AdvancedSwitch<T>, which allows you to add cases and exposes a method to evaluate a value and lets you specify values that it should check for existence.
This is what I came up with:
public class AdvancedSwitch<T> where T : struct
{
protected Dictionary<T, Action> handlers = new Dictionary<T, Action>();
public void AddHandler(T caseValue, Action action)
{
handlers.Add(caseValue, action);
}
public void RemoveHandler(T caseValue)
{
handlers.Remove(caseValue);
}
public void ExecuteHandler(T actualValue)
{
ExecuteHandler(actualValue, Enumerable.Empty<T>());
}
public void ExecuteHandler(T actualValue, IEnumerable<T> ensureExistence)
{
foreach (var val in ensureExistence)
if (!handlers.ContainsKey(val))
throw new InvalidOperationException("The case " + val.ToString() + " is not handled.");
handlers[actualValue]();
}
}
You can consume the class this way:
public enum TrafficColor { Red, Yellow, Green }
public static void Main()
{
Console.WriteLine("Choose a traffic color: red, yellow, green?");
var color = (TrafficColor)Enum.Parse(typeof(TrafficColor), Console.ReadLine());
var result = string.Empty;
// Creating the "switch"
var mySwitch = new AdvancedSwitch<TrafficColor>();
// Adding a single case
mySwitch.AddHandler(TrafficColor.Green, delegate
{
result = "You may pass.";
});
// Adding multiple cases with the same action
Action redAndYellowDelegate = delegate
{
result = "You may not pass.";
};
mySwitch.AddHandler(TrafficColor.Red, redAndYellowDelegate);
mySwitch.AddHandler(TrafficColor.Yellow, redAndYellowDelegate);
// Evaluating it
mySwitch.ExecuteHandler(color, (TrafficColor[])Enum.GetValues(typeof(TrafficColor)));
Console.WriteLine(result);
}
With the creative use of anonymous delegates, you can easily add new cases to your "switch block". :)
Not that you can also use lambda expressions, and lambda blocks, eg () => { ... } instead of delegate { ... }.
You can easily use this class instead of the long switch blocks.
Original post:
If you use Visual Studio, always create swich statements with the switch code snippet. Type switch press tab twice, and it auto-generates all the possibilities for you.
Then, add a default case to the end which throws an exception, that way when testing your app you will notice that there is an unhandled case, instantly.
I mean something like this:
switch (something)
{
...
case YourEnum.SomeValue:
...
break;
default:
throw new InvalidOperationException("Default case reached.");
}
Well, there's throwing in the default case... There's no edit / compile time construct other than that.
However Strategy, Visitor and other patterns related to them may be appropriate if you choose to do it at run time.
Sample code will help with getting the best answer.
EDIT: Thanks for the sample. I still think it needs a bit of fleshing out as you dont cover whether there are some parameters that only apply to some cases etc.
Action is often used as an alias for the Command pattern and the fact that your Enum is called LogAction signifies that each value carries with it a behavior - be that implied (you stick appropriate code in a case) or explicit (in the specific Command hierarchy class).
Thus it looks to me like a usage of the Command pattern is appropriate (though your sample doesnt prove it) - i.e., have a class (potentially a hierarchy using constructor overloads or any other [set of] factory mechanisms) that keeps the state associated with the request along with the specific behaviour. Then, instead of passing an Enum value, create an appropriate LogCommand instance to the logger, which just invokes it (potentially passing a Log Sink 'receptacle' which the Command can log into). Otherwise you're poking random subsets of parameters in different places.
SEEALSO related posts:
C# - Is there a better alternative than this to ‘switch on type’?
Replace giant switch statement with what?
One possible solution is to use a SortedDictionary:
delegate void EnumHandler (args);
SortedDictionary <Enum, EnumHandler> handlers;
constructor
{
handlers = new SortedDictionary <Enum, EnumHandler> ();
fill in handlers
}
void SomeFunction (Enum enum)
{
EnumHandler handler;
if (handlers.TryGetValue (enum, out handler))
{
handler (args);
}
else
{
// not handled, report an error
}
}
This method does allow you to replace the handlers dynamically. You could also use a List as the value part of the dictionary and have multiple handlers for each enum.
Try to use reflection.
Decorate enum options with attributes that holds associated value and return this value.
Create static class of constants and use reflection for mapping enum-option to constant by name
hope this will help
Some times storing the options in a map is a good solution, you can externalize the configuration to a file too, not sure if it applies to your application.
Long code example here, and the final generic code is a little heavy (EDIT have added an extra example that eliminates the need for the angle brackets at the expense of some final flexibility).
One thing that this solution will give you is good performance - not quite as good as a straightforward switch statement, but each case statement becomes a dictionary lookup and method invocation, so still pretty good. The first call will get a performance penalty, however, due to the use of a static generic that reflects on initialisation.
Create an attribute and generic type as follows:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class DynamicSwitchAttribute : Attribute
{
public DynamicSwitchAttribute(Type enumType, params object[] targets)
{ Targets = new HashSet<object>(targets); EnumType = enumType; }
public Type EnumType { get; private set; }
public HashSet<object> Targets { get; private set; }
}
//this builds a cache of methods for a given TTarget type, with a
//signature equal to TAction,
//keyed by values of the type TEnum. All methods are expected to
//be instance methods.
//this code can easily be modified to support static methods instead.
//what would be nice here is if we could enforce a generic constraint
//on TAction : Delegate, but we can't.
public static class DynamicSwitch<TTarget, TEnum, TAction>
{
//our lookup of actions against enum values.
//note: no lock is required on this as it is built when the static
//class is initialised.
private static Dictionary<TEnum, TAction> _actions =
new Dictionary<TEnum, TAction>();
private static MethodInfo _tActionMethod;
private static MethodInfo TActionMethod
{
get
{
if (_tActionMethod == null)
{
//one criticism of this approach might be that validation exceptions
//will be thrown inside a TypeInitializationException.
_tActionMethod = typeof(TAction).GetMethod("Invoke",
BindingFlags.Instance | BindingFlags.Public);
if (_tActionMethod == null)
throw new ArgumentException(/*elided*/);
//verify that the first parameter type is compatible with our
//TTarget type.
var methodParams = _tActionMethod.GetParameters();
if (methodParams.Length == 0)
throw new ArgumentException(/*elided*/);
//now check that the first parameter is compatible with our type TTarget
if (!methodParams[0].ParameterType.IsAssignableFrom(typeof(TTarget)))
throw new ArgumentException(/*elided*/);
}
return _tActionMethod;
}
}
static DynamicSwitch()
{
//examine the type TTarget to extract all public instance methods
//(you can change this to private instance if need be) which have a
//DynamicSwitchAttribute defined.
//we then project the attributes and the method into an anonymous type
var possibleMatchingMethods =
from method in typeof(TTarget).
GetMethods(BindingFlags.Public | BindingFlags.Instance)
let attributes = method.GetCustomAttributes(
typeof(DynamicSwitchAttribute), true).
Cast<DynamicSwitchAttribute>().ToArray()
where attributes!= null && attributes.Length == 1
&& attributes[0].EnumType.Equals(typeof(TEnum))
select new { Method = method, Attribute = attributes[0] };
//create linq expression parameter expressions for each of the
//delegate type's parameters
//these can be re-used for each of the dynamic methods we generate.
ParameterExpression[] paramExprs = TActionMethod.GetParameters().
Select((pinfo, index) =>
Expression.Parameter(
pinfo.ParameterType, pinfo.Name ?? string.Format("arg{0}"))
).ToArray();
//pre-build an array of these parameter expressions that only
//include the actual parameters
//for the method, and not the 'this' parameter.
ParameterExpression[] realParamExprs = paramExprs.Skip(1).ToArray();
//this has to be generated for each target method.
MethodCallExpression methodCall = null;
foreach (var match in possibleMatchingMethods)
{
if (!MethodMatchesAction(match.Method))
continue;
//right, now we're going to use System.Linq.Expressions to build
//a dynamic expression to invoke this method given an instance of TTarget.
methodCall =
Expression.Call(
Expression.Convert(
paramExprs[0], typeof(TTarget)
),
match.Method, realParamExprs);
TAction dynamicDelegate = Expression.
Lambda<TAction>(methodCall, paramExprs).Compile();
//now we have our method, we simply inject it into the dictionary, using
//all the unique TEnum values (from the attribute) as the keys
foreach (var enumValue in match.Attribute.Targets.OfType<TEnum>())
{
if (_actions.ContainsKey(enumValue))
throw new InvalidOperationException(/*elided*/);
_actions[enumValue] = dynamicDelegate;
}
}
}
private static bool MethodMatchesAction(MethodInfo method)
{
//so we want to check that the target method matches our desired
//delegate type (TAction).
//The way this is done is to fetch the delegate type's Invoke
//method (implicitly invoked when you invoke delegate(args)), and
//then we check the return type and parameters types of that
//against the return type and args of the method we've been passed.
//if the target method's return type is equal to or derived from the
//expected delegate's return type, then all is good.
if (!_tActionMethod.ReturnType.IsAssignableFrom(method.ReturnType))
return false;
//now, the parameter lists of the method will not be equal in length,
//as our delegate explicitly includes the 'this' parameter, whereas
//instance methods do not.
var methodParams = method.GetParameters();
var delegateParams = TActionMethod.GetParameters();
for (int i = 0; i < methodParams.Length; i++)
{
if (!methodParams[i].ParameterType.IsAssignableFrom(
delegateParams[i + 1].ParameterType))
return false;
}
return true;
}
public static TAction Resolve(TEnum value)
{
TAction result;
if (!_actions.TryGetValue(value, out result))
throw new ArgumentException("The value is not mapped");
return result;
}
}
Now do this in a Unit Test:
[TestMethod]
public void TestMethod1()
{
Assert.AreEqual(1,
DynamicSwitch<UnitTest1, Blah, Func<UnitTest1, int>>.
Resolve(Blah.BlahBlah)(this));
Assert.AreEqual(125,
DynamicSwitch<UnitTest1, Blah, Func<UnitTest1, int>>.
Resolve(Blah.Blip)(this));
Assert.AreEqual(125,
DynamicSwitch<UnitTest1, Blah, Func<UnitTest1, int>>.
Resolve(Blah.Bop)(this));
}
public enum Blah
{
BlahBlah,
Bloo,
Blip,
Bup,
Bop
}
[DynamicSwitchAttribute(typeof(Blah), Blah.BlahBlah)]
public int Method()
{
return 1;
}
[DynamicSwitchAttribute(typeof(Blah), Blah.Blip, Blah.Bop)]
public int Method2()
{
return 125;
}
So, given a value of TEnum, and your preferred 'action' type (in your code you would appear to be simply returning nothing and modifying the internal state of the class), you simply consult the DynamicSwitch<> class, ask it to resolve a target method, and then invoke it inline (passing the target object on which the method will be invoked as the first parameter).
I'm not really expecting any votes for this - it's a MAD solution to be honest (it does have the advantage of being able to be applied for any enum type, and even discreet values of type int/float/double, as well as supporting any delegate type) - so perhaps it's a bit of a sledgehammer!
EDIT
Once you have a static generic like this, angle-bracket hell ensues - so we want to try and get rid of them. A lot of the time, this is done by type inference on method parameters etc - but we have a problem here that we can't easily infer a delegate's signature without repeating the method call i.e. (args) => return.
However, you seem to require a method that takes no parameters and returns void, so you can close over this behemoth generic by fixing the delegate type to Action, and throw a fluid API into the mix as well (if that's your kind of thing):
public static class ActionSwitch
{
public class SwitchOn<TEnum>
{
private TEnum Value { get; set; }
internal SwitchOn(TEnum value)
{
Value = value;
}
public class Call<TTarget>{
private TEnum Value { get; set; }
private TTarget Target { get; set; }
internal Call(TEnum value, TTarget target)
{
Value = value;
Target = target;
Invoke();
}
internal void Invoke(){
DynamicSwitch<TTarget, TEnum, Action<TTarget>>.Resolve(Value)(Target);
}
}
public Call<TTarget> On<TTarget>(TTarget target)
{
return new Call<TTarget>(Value, target);
}
}
public static SwitchOn<TEnum> Switch<TEnum>(TEnum onValue)
{
return new SwitchOn<TEnum>(onValue);
}
}
Now add this to the test project:
[TestMethod]
public void TestMethod2()
{
//no longer have any angle brackets
ActionSwitch.Switch(Blah.Bup).On(this);
Assert.IsTrue(_actionMethod1Called);
}
private bool _actionMethod1Called;
[DynamicSwitch(typeof(Blah), Blah.Bup)]
public void ActionMethod1()
{
_actionMethod1Called = true;
}
Only issue with this (apart from the complexity of the solution :) ) is that you'd have to re-build this static wrapper type whenever you want to use a new type of target delegate for a dynamic switch elsewhere. You could generate a generic version based on the Action<...> and Func<...> delegates that incorporates TArg1, TArg(n) and TReturn (if Func<>) - but you'd end up writing a lot more code.
Perhaps I'll turn this into an article on my blog and do all of that - if I get the time!

Categories