if I have a delegate like so:
Delegate void Render();
Render ToRender;
And use it here:
ToRender += FunctionRender;
ToRender += SomeOtherRender;
How can I make it so I can invoke each function seperately? Something like this:
foreach(Render render in ToRender)
{
BeginRender();
render();
EndRender();
}
You can fetch each one separately using Delegate.GetInvocationList().
foreach (Render render in ToRender.GetInvocationList())
{
...
}
Note that GetInvocationList() just returns a Delegate[], but foreach has an implicit cast on each item, which is what makes the above loop work.
Oh, and you should check whether ToRender is null or not first, of course - otherwise you'll get a NullReferenceException. You could actually write a generic extension method to make this nicer, but you'd need a constraint on the delegate type which isn't allowed in C# :(
If you don't care about the lack of constraints, you could fake it:
public static IEnumerable<T> GetIndividualDelegates<T>(this T multiDelegate)
where T : class
{
if (multiDelegate == null)
{
yield break;
}
Delegate d = (Delegate)(object) multiDelegate;
foreach (Delegate item in d.GetInvocationList())
{
yield return (T)(object) item;
}
}
(It's awkward because of the restrictions on generic conversions.)
That way you could write:
foreach (Render render in ToRender.GetIndividualDelegates())
{
...
}
without worrying about whether ToRender was null or not.
foreach (Render render in ToRender.GetInvocationList())
Ideal Way:
Render temp = ToRender;
if (temp != null)
{
foreach (Render render in temp.GetInvocationList())
{
BeginRender();
render();
EndRender();
}
}
ToRender.GetInvocationList returns an array of all delegates contained on the "list".
thats not how delegates and events work. all methods will automatically be invoked by the framework. event handlers should be able to be executed completely independent of any other handlers. if you need to control the flow more tightly, you should think about redesigning your approach.
perhaps 3 events/delegates - similar to the way asp.net does it. PreRender, Render and PostRender. im not sure what you are doing, but this sounds like overkill to me. just thought i would throw it out.
Related
Introduction
I'm using delegates to pass along and store styling logic for individual form Controls. For example, I have a delegate containing some Button-styling logic like this:
button.BackColor = Color.Red;
button.ForeColor = Color.White;
button.FlatStyle = FlatStyle.Flat;
Of course there are many different other type of controls, like Labels, Panels, etc. So to store all these delegates I use a Dictionary<Type, Delegate>.
Although, the delegate itself looks like this:
delegate void StyleDel<in T>(T control) where T : Control;
So in order to use the logic inside the dictionary, the Delegate must be cast to StyleDel<T> first - whatever T might be at that moment.
The situation
After all of the styling is initialised and stored, the styling must be applied (using the StyleDels). For this I made a function StyleControl(control).
This function looks at the type of the control (e.g. a Button) and finds the corresponding StyleDel from the Dictionary, which in its turn applies the (Button-)styling.
public void StyleControl<T>(T control) where T : Control
{
Delegate storedDel;
if (_dict.TryGetValue(control.GetType(), out storedDel))
{
// Cast Delegate to StyleDel
var styleDel = (StyleDel<T>) storedDel;
// Execute StyleDel
styleDel(control);
}
}
The StyleDels are added to the dictionary with the Add function below:
public bool Add<T>(StyleDel<T> styleDel) where T : Control
{
var inDict = _dict.ContainsKey(typeof(T));
if (!inDict) _dict[typeof(T)] = styleDel;
return !inDict;
}
And the StyleControl function is called by another function, which makes sure everything is styled recursively:
public void Style<T>(T parent) where T : Control
{
StyleControl(parent);
// The problem might have to do with this
foreach (Control child in parent.Controls) Style(child);
}
The problem
An InvalidCastException is thrown, saying a StyleDel<Button> cannot be converted to StyleDel<Control>. So I believe it's saying that T is seen as a Control at this point, while it's actually a Button.
How do I cast this Delegate to a StyleDel<Button> successfully?
You can achieve this by adding a level of inderection; create a lambda that calls your delegate casting the argument to the right type:
Dictionary<Type, StyleDel<Control>> _dict = ...
public bool Add<T>(StyleDel<T> styleDel) where T : Control
{
var inDict = _dict.ContainsKey(typeof(T));
if (!inDict) _dict[typeof(T)] = d => StyleDel((T)d);
return inDict;
}
At first glance this might seem to not be type safe, but in this particular case it will be because the delegate is stored in a dictionary with the argument's true type as it's key. Intended usage will therefore always ensure that the delegate is always called with a correctly typed argument and a runtime cast exception will not happen.
I am making some validation functions for my project but I am stuck on something.
I want to have a single function to handle a couple of different controls and errors.
Here's my code:
private void ValidateControls(Control c)
{
if (c is TextBox)
{
if (c.Text == "")
{
epNew.SetError(c, "Something");
}
}
else if (c is ComboBox)
{
// What now?
// if (c.SelectedItem == null) does not work
}
}
And I am calling it like this:
private void txtNEAN_Validating(object sender, CancelEventArgs e)
{
ValidateControls(txtNEAN);
}
This works fine for textboxes. But if I do:
private void cbbEMerk_Validating(object sender, CancelEventArgs e)
{
ValidateControls(cbbEMerk);
}
if (c.SelectedItem == null) for example does not work.
How can I achieve this? And is this okay to use? If not, what is a better alternative?
I'd love to hear anything!
You have to cast c to a ComboBox in this case
else if (c is ComboBox)
{
if (((ComboBox)c).SelectedItem == null)
}
By the way, don't create a _Validating method for every control if they do the same thing. You can use a single one, or one txtBox_Validating for TextBoxes, one comboBox_Validating for comboboxes, etc.
Try using
((ComboBox)c).SelectedItem
instead. This tells the program to parse the Control c into a ComboBox.
As an alternative, instead of using is you could use as
// Converts c to a ComboBox. If c is not a ComboBox, assigns null to cmbControl
ComboBox cmbControl = c as ComboBox;
if (cmbControl != null)
{
if (cmbControl.SelectedItem != null)
{
// Do stuff here
}
}
// Else it's not a ComboBox
It is also good to know about safety cast using as and is:
Because objects are polymorphic, it is possible for a variable of a base class type to hold a derived type. To access the derived type's method, it is necessary to cast the value back to the derived type. However, to attempt a simple cast in these cases creates the risk of throwing an InvalidCastException. That is why C# provides the is and as operators. You can use these operators to test whether a cast will succeed without causing an exception to be thrown. In general, the as operator is more efficient because it actually returns the cast value if the cast can be made successfully. The is operator returns only a Boolean value. It can therefore be used when you just want to determine an object's type but do not have to actually cast it.
You can see more here
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How to pass an event to a method?
Is it possible to pass an event as a parameter to a method?
For example, the following method subscribes to the event, does work, and unsubscribes from the event:
void SubscribeDoAndUnsubscribe<TElement, TEventArgs>(
IEnumerable<TElement> elements,
??? elementEvent)
where TEventArgs: EventArgs
{
EventHandler<TEventArgs> handler = (sender, e) => { /* Handle an event */ };
foreach (var element in elements)
{
// Subscribe somehow
element.elementEvent += handler
}
// Do things
foreach (var element in elements)
{
// Unsubscribe somehow
element.elementEvent -= handler
}
}
Client code:
var elements = new [] { new Button(), new Button() };
SubscribeDoAndUnsubscribe(elements, ??? /* e => e.Click */);
If it's not possible, how do I achieve the similar logic in other ways? Shall I pass pair of delegates for subscribe/unsubscribe methods?
You have in fact discovered that events are not "first class" in C#; you cannot pass around an event as data. You can pass around a delegate to a method associated with a receiver as a first-class object by making a delegate. You can pass around a reference to any variable as a (mostly) first-class object. (I say "mostly" because references to variables cannot be stored in fields, stored in arrays, and so on; they are highly restricted compared to other kinds of data.) You can pass around a type by obtaining its Type object and passing that around.
But there is no way to directly pass around as data an event, property, indexer, constructor or destructor associated with a particular instance. The best you can do is to make a delegate (or pair of delegates) out of a lambda, as you suggest. Or, obtain the reflection object associated with the event and pass that around, along with the instance.
No, unfortunately not.
If you look at Reactive Extensions, that suffers from a similar problem. Three options they use (IIRC - it's been a while since I've looked):
Pass in the corresponding EventInfo and call it with reflection
Pass in the name of the event (and the target if necessary) and call it with reflection
Pass in delegates for subscription and unsubscription
The call in the latter case would be something like:
SubscribeAndDoUnsubscribe(elements,
handler => e.Click += handler,
handler => e.Click -= handler);
and the declaration would be:
void SubscribeDoAndUnsubscribe<TElement, TEventArgs>(
IEnumerable<TElement> elements,
Action<EventHandler<TEventArgs>> subscription,
Action<EventHandler<TEventArgs>> unsubscription)
where TEventArgs: EventArgs
You're trying to get around type safety, and you can't do so without using reflection. I'll show you an even simpler example of what you're trying to do.
void DoSomethingOnSomethingElse(T obj, Action method)
{
obj.method();
}
C# doesn't work this way. How does the compiler know that all Ts have the method method? It doesn't, and can't. Similarly, not every TElement in your code will have an event Click for example.
It sounds like you just want to set a single use event handler on a set of objects. You can do this quite easily...
EventHandler handler = null;
handler = (s,e) =>
{
DoSomething(e);
var b = (Button) s;
b.Click -= handler;
}
foreach (var button in buttons)
{
button.Click += handler;
}
This, obviously, only works with buttons, but as I write this, I see Jon Skeet has shown you a more general solution, so I'll end here.
I have a function that takes a control as parameter, and depending on the control's type (e.g.: TextBox, ComboBox, RadioButton etc...), it executes type-specific code:
internal static void DoSomething(Control control)
{
if (control is Button)
{
// code for button
}
else if (control is CheckBox)
{
// code for CheckBox
}
else if (control is TextBox)
{
// code for TextBox
}
// etc.....
}
I am wondering if this is the best way to do.
I know of some other ways to do the same thing (e.g.: looking for the control's type using GetType(), switching on the string representation of this type), and Microsoft's code analysis tool tells me to use 'as' instead of 'is' like this (because it is better performance-wise):
internal static void DoSomething(Control control)
{
Button button = control as Button
if (button != null)
{
// code for button
}
else
{
CheckBox checkBox = control as CheckBox;
if (checkBox != null)
{
// code for CheckBox
}
else
{
TextBox textBox = control as TextBox;
if (textBox != null)
{
// code for TextBox
}
// etc.....
}
}
}
but I find this last solution rather wordy and not very practical to read.
I'd like to be able to switch on the control's type directly, but am unable do to so without resorting to use the string representation (which I don't like at all) as a switch's case statement cannot contain a variable.
So what really is the best way to do performance-wise? and what is, in you opinion, the best way to do? (not necessarily performance-wise, but "code-readability-wise" for instance)
Edit: as a lot is going on on the subject of "why do I use one common function and not many type-specific methods", here is some more info:
I get a control variable from an other part of the app I'm working on (type = Control) and I have do "do something" with this variable, depending on its type.
so basically, I have the choice between 2 options: either I use one common function and check the control's type in the function's body so that I execute the right portion of the code at some point (options I have chosen for now, but this could change), or I check for the control's type BEFORE calling a type-specific method.
either way, I have to switch on the control's type at some point, and THIS is the subject of my question (regardless of what I do with it, if I may say so).
I would use Dictionary for it and (also separate methods for each handler):
private static readonly Dictionary<Type, Action<Control>> _handlers
= new Dictionary<Type, Action<Control>>();
// Handle.. methods
private static void HandleButton(Button button) { ... }
private static void HandleListbox(Listbox listbox) { ... }
private static void RegisterHandler<T>(Action<T> handler)
where T: Control
{
_handlers.Add(typeof(T), o => handler((T)o));
}
// invoke this method in static constructor
private static void InitializeHandlers()
{
RegisterHandler<Button>(HandleButton);
RegisterHandler<Listbox>(HandleListbox);
}
// finally usage:
internal static void DoSomething(Control control)
{
var handler = _handlers[control.GetType()];
handler(control);
}
The benefit for this approach is some maintainability improvement:
1. You will know that you haven't registered several handlers for same parameter type (dictionary will throw an exception)
2. You will have all your handler registrations separately which will allow you easily finding out which method handles particular parameter type.
3. Since all handler locating logic is not repeated at all it is pretty easy to modify it in order to handle inhereting types for example (my code doesn't do this but your code did)
Well, you don't need to nest on the second one use else if.
Second why are you putting all of this into one method? It would be better since at the time that you are calling this you should know what the type of the control that it is calling this method is and from there just Do the DoSomething for that control type instead of all of this conditional checking.
I think you're fine using the "is" operator here. It's more readable, and you don't really have any useful alternate path in the case that the control isn't what you were looking for anyway. I don't believe the timing differences will be that critical in this case.
You could swap out the "else if"s for a series of plain "if"s by returning from each individual if block, but that's a personal style choice.
It would be better to refactor the generic (control-agnostic) functionality into a separate function, and have the control-specific functionality in control-specific functions.
You can then call the generic function from the control-specific function where appropriate.
This is the kind of solution I would opt for:
internal class MyClass
{
private const string ButtonTypeAsString = "Button";
private const string CheckBoxTypeAsString = "CheckBox";
private const string TextBoxTypeAsString = "TextBox";
private static string GetTypeAsString(Control control)
{
string result = String.empty;
if (result.Length == 0 && (control as Button) != null)
{
result = MyClass.ButtonTypeAsString;
}
if (result.Length == 0 && (control as CheckBox) != null)
{
result = MyClass.CheckBoxTypeAsString;
}
if (result.Length == 0 && (control as TextBox) != null)
{
result = MyClass.TextBoxTypeAsString;
}
if (result.Length == 0)
{
throw new InvalidOperationException("Control type is not handled by this method.");
}
return result;
}
internal static void DoSomething(Control control)
{
string controlTypeAsString = MyClass.GetTypeAsString(control);
switch (controlTypeAsString)
{
case MyClass.ButtonTypeAsString:
// Button stuff
break;
case MyClass.CheckBoxTypeAsString:
// Checkbox stuff
break;
case MyClass.TextBoxTypeAsString:
// TextBox stuff
break;
default:
throw new InvalidOperationException("Unexpected Control type");
}
}
}
... but I'm sure some would find this overkill. Personally, I like the readability of the switch statement and try to use it whenever possible. Also, avoiding switching on "Magic Strings." Use const strings when possible.
If you don't mind me asking, what is it exactly you're trying to do? There may be a better solution that doesn't involve having to infer a Control's type.
Is there any best practice with respect to coding style with respect to explicit use of the delegate keyword instead of using a lambda?
e.g.
new Thread(() =>
{
// work item 1
// work item 2
}).Start();
new Thread(delegate()
{
// work item 1
// work item 2
}).Start();
I think the lambda looks better. If the lambda is better style, what's the point of having a delegate keyword, other than for the fact that it existed before lambdas were implemented?
Lambda syntax is much more generalised, and the designers have said that they'd ideally remove the old overlapping syntaxes (dont have a citation, but it's probably Eric Lippert or Jon Skeet in a book or a podcast).
But delegate allows you to ignore parameters, e.g.:
object.Event += delegate { };
versus having to say:
object.Event += (sender,args) => { };
which can be very useful in large argument lists and/or to make the code more resilient to refactoring.
EDIT: As pointed out by Yann Schwartz in another answer (now unfortunately deleted), a very neat usage of this trick is in order to provide a default hander for an event using the Null Object pattern:-
class MyClassThatFiresWithoutTheTrick
{
public event EventHandler MyEvent; // implicit = null
// Need a method to keep this DRY as each fire requires a null check - see Framework Design Guidelines by Abrams and Cwalina
protected virtual void OnMyEvent()
{
// need to take a copy to avoid race conditions with _removes
// See CLR via C# 3rd edition p 264-5 for reason why this happens to work
//var handler = MyEvent;
// BUT THIS is the preferred version
var handler = Interlocked.CompareExchange( ref MyEvent, null, null);
// Need to do this check as it might not have been overridden
if( handler == null)
return;
handler( this, EventArgs.Empty );
}
}
class MyClassThatFiresWithTheTrick
{
public event EventHandler MyEvent = delegate{};
protected virtual void OnMyEvent()
{
MyEvent( this, EventArgs.Empty );
}
}
(though what you might often end up doing is an Inline Method of OnMyEvent, making the code even shorter again.)