How can I restrict a function argument to a some specific enums? Preferably check it at compile-time (though I doubt this is possible).
What I have are 2 enums (KeyCode for keyboard keys and Mouse.Button for mouse buttons) and they are treated in the code in exactly the same way. I could simply overload the function and copy-paste the contents, but well, I'd like to avoid the nightmares.
Simplified version of what I currently have (inside a class)
enum E1 { Zero, One, Two }
enum E2 { Three, Four, Five }
// Overloads so users can only use this with enums only of type E1 or E2
public void DoEnumStuff(E1 e) {
DoEnumStuffTemplate(e);
}
public void DoEnumStuff(E2 e) {
DoEnumStuffTemplate(e);
}
// private function so users cannot access this generic one
private void DoEnumStuffTemplate<T>(T e) where T : struct, IConvertible {
// check type for safety
if (!typeof(T).IsEnum || typeof(T).Name != "E1" || typeof(T).Name != "E2")
throw new ArgumentException();
// do lots of stuff
DoSomething(e); //<- overloaded function, accepts only E1 and E2 =ERROR
// do lots of other stuff
}
For completeness sake:
DoSomething behaves completely different depending on which type is given
DoSomething is called a lot in the function
I cannot change the Enums
I do not want to change DoSomething
I think I need to be able to tell the compiler that the generic T is surely either E1 or E2, but I have no clue as of how to do this.
Edit: the situation
Lots of good suggestions, but nothing that encompasses all I want. I'll add here the code I currently have to shed some more light on the problem hopefully.
I'm making a minesweeper clone to try out Unity 2D. I've created an Action class based on the thor::ActionMap class from the library Thor in C++ used with SFML. It simply allows for neat code such as (in C++)
ActionMap actionMap<string>;
actionMap["Fire"] = Action(Keyboard::LeftControl) || Action(Mouse::Left);
// stuff
while (game.IsRunning()) {
if (actionMap["Fire"].IsActive()) //true if left control or left mouse button is held
// FIRE
// probably more stuff
}
Where ActionMap is simply a dictionary of a key (here a string) and an Action. As you can see, the Action accepts both keyboard and mouse buttons which are 2 different enums. Thus the equivalent of the DoSomething(e) from the example code.
I'm now creating a method that can change the controls consistently. It uses the enum EControls as key instead of a string. Here KeyCode contains all keyboard keys and Mouse.Button all the mouse buttons. I need to differentiate between pressing and releasing of a button here, which is why both EControls.TilePressed and EControls.TileReleased will have the same key and need to be treated differently than for example EControls.GameEscape. This code is again in C#.
private ActionMap _controls = new ActionMap<EControls>();
// Set controls for a keyboard key
public void SetControl(EControls control, KeyCode key) {
switch (control) {
// If either TilePressed or Released was given, set them both to the same key
case EControls.TilePressed:
case EControls.TileReleased:
//Here Action(...) is DoSomething(...) from the example code
_controls[EControls.TilePressed] = new Action(key, Action.EActionType.PressOnce);
_controls[EControls.TileReleased] = new Action(key, Action.EActionType.ReleaseOnce);
break;
case EControls.TileFlagPressed:
case EControls.TileFlagReleased:
_controls[EControls.TileFlagPressed] = new Action(key, Action.EActionType.PressOnce);
_controls[EControls.TileFlagReleased] = new Action(key, Action.EActionType.ReleaseOnce);
break;
case EControls.GameEscape:
_controls[EControls.GameEscape] = new Action(key, Action.EActionType.ReleaseOnce);
break;
default:
throw new ArgumentOutOfRangeException("control");
}
}
// Set controls for a mouse button
public void SetControl(EControls control, Mouse.Button button) {
// copy-pasted code :(
case EControls.TilePressed:
case EControls.TileReleased:
_controls[EControls.TilePressed] = new Action(button, Action.EActionType.PressOnce);
_controls[EControls.TileReleased] = new Action(button, Action.EActionType.ReleaseOnce);
break;
case EControls.TileFlagPressed:
case EControls.TileFlagReleased:
_controls[EControls.TileFlagPressed] = new Action(button, Action.EActionType.PressOnce);
_controls[EControls.TileFlagReleased] = new Action(button, Action.EActionType.ReleaseOnce);
break;
case EControls.GameEscape:
_controls[EControls.GameEscape] = new Action(button, Action.EActionType.ReleaseOnce);
break;
default:
throw new ArgumentOutOfRangeException("control");
}
}
As you can see, in almost every line of code new Action(...) is present and code such as if (typeof(T).GetType() == typeof(E1)) is essentially the same as copy-pasting the contents of the function. Which is something I'd like to avoid (copy-pasting would even be safer on compile-time). But as it stands, it does not seem to be possible.
Since in a bigger game you'll probably regularly add some new controls, it will be quite an annoyance.
Sorry for the wall of text :s
Here's a refactoring that resembles the Factory pattern:
public void SetControl(EControls control, Func<Action.EActionType, Action> createAction)
{
switch (control)
{
case EControls.TilePressed:
case EControls.TileReleased:
_controls[EControls.TilePressed] = createAction(Action.EActionType.PressOnce);
_controls[EControls.TileReleased] = createAction(Action.EActionType.ReleaseOnce);
break;
case EControls.TileFlagPressed:
case EControls.TileFlagReleased:
_controls[EControls.TileFlagPressed] = createAction(Action.EActionType.PressOnce);
_controls[EControls.TileFlagReleased] = createAction(Action.EActionType.ReleaseOnce);
break;
case EControls.GameEscape:
_controls[EControls.GameEscape] = createAction(Action.EActionType.ReleaseOnce);
break;
default:
throw new ArgumentOutOfRangeException("control");
}
}
// Call it later with:
SetControl(control, type => new Action(key, type));
SetControl(control, type => new Action(mouseButton, type));
You provide SetControl with what amounts to a partially filled constructor, createAction, that only needs the EActionType to fully create the Action.
Another way to do this (while changing more code) would be to invert the dependency: give the Action a way to set its own EActionType based on a passed in EControls.
I think overloading is your best bet. Factor do lots of stuff and do lots of other stuff into methods of their own, and you won't have any nightmares.
If that's really impossible, then what you have is fine. Just cast e to either E1 or E2 as appropriate. It's a little gross, but it's a private method so the ugliness shouldn't spread too far.
An ugly, but a way:
private void DoEnumStuffTemplate<T>(T e) where T : struct, IConvertible
{
if (typeof(T) == typeof(E1))
DoEnumStuff((E1)(object)e);
else if (typeof(T) == typeof(E2))
DoEnumStuff((E2)(object)e);
else
throw new ArgumentException();
}
Make sure nobody see it.
You don't want to change DoSomething, but would wrapping it be ok?
private void myDoSomething(T e) where T : struct, IConvertible
{
if (typeof(T).GetType().Name == "E1")
DoSomething((E1)(object)e);
else if (typeof(T).GetType().Name == "E2")
DoSomething((E2)(object)e);
else
throw new ArgumentException();
}
// private function so users cannot access this generic one
private void DoEnumStuffTemplate<T>(T e) where T : struct, IConvertible {
// check type for safety
if (!typeof(T).IsEnum || typeof(T).GetType().Name != "E1" || typeof(T).GetType().Name != "E2")
throw new ArgumentException();
// do lots of stuff
myDoSomething(e); //<- overloaded function, accepts only E1 and E2 =ERROR
// do lots of other stuff
}
You need to create the Action in two steps. The caller of SetControl(...) knows whether the source is a mouse button or a key. So the caller creates the action object like new Action(key) or new Action(button).
This action object is passed to the SetControl(control, Action action) method.
SetControl knows the action type. It needs a method in Action where the action type can be set, e.g. Action.SetActionType(Action.EActionType actionType).
So the SetControl method is:
// Set controls for an action
public void SetControl(EControls control, Action action) {
switch (control) {
// If either TilePressed or Released was given, set them both to the same key
case EControls.TilePressed:
case EControls.TileReleased:
//Here Action(...) is DoSomething(...) from the example code
_controls[EControls.TilePressed] = action.SetActionType(Action.EActionType.PressOnce);
_controls[EControls.TileReleased] = action.SetActionType(Action.EActionType.ReleaseOnce);
break;
case EControls.TileFlagPressed:
case EControls.TileFlagReleased:
_controls[EControls.TileFlagPressed] = action.SetActionType(Action.EActionType.PressOnce);
_controls[EControls.TileFlagReleased] = action.SetActionType(Action.EActionType.ReleaseOnce);
break;
case EControls.GameEscape:
_controls[EControls.GameEscape] = action.SetActionType(Action.EActionType.ReleaseOnce);
break;
default:
throw new ArgumentOutOfRangeException("control");
}
}
This method is called like so:
SetControl(control, new Action(key));
SetControl(control, new Action(mouseButton));
Related
I am trying to call a function based on information from a combobox. The user will change the combobox and in doing so we call a function according to the data in the combobox text joined with a fixed text. I am trying to do this so every time we get a new version I just add a folder and do not have to go into the code to add new function names like in a case statement.
The combobox would have text as
v6.1
v6.4
v7.2
v8.6
and so on
The function I want to call is named Getinfo_ with the addition of the text from the combobox with the . replaced with _ e.g. I would choose v6.1 from combobox and in doing so I would call function called Getinfo_v6_1
After a lot of thinking searching and trying I have got close but not close enough yet. I think I need to use Reflection (maybe not) and
private void cmbobx_version_SelectedIndexChanged(object sender, EventArgs e)
{
Type t = this.GetType(); //need to get the type
MethodInfo method = t.GetMethod("Getinfo" + cmbobx_version.Text.Replace('.', '_')); //put together function name
method.Invoke(this, new object[] {Fridge, "Order" }); //call function with parameters
}
Unfortunately this stops at invoke saying the method is NULL, I do not understand why this is so apart from maybe I totally misunderstand what I am doing.
The function I want to call would look a bit like the following
public void Getinfo_v6_1(ComboBox inFocusComboBox, string action)
{
switch (inFocusComboBox.Text)
{
case "Red": Price = 11254; break;
case "Blue": Price = 11278; break;
case "Green": Price = 11354; break;
}
}
public void Getinfo_v6_4(ComboBox inFocusComboBox, string action)
{
switch (inFocusComboBox.Text)
{
case "Red": Price = 254; break;
case "Blue": Price = 278; break;
case "Green": Price = 354; break;
}
}
All help greatly appreciated even if you have a better way of doing what I need to do.
You should read about design patterns for example you could create polymorphic items that implement your function using for example the template design pattern. Try to avoid reflection as it is ‘slow’ and not type safe.
Thanks to Ĵošħ Williard I had indeed missed out the underscore and when working with it I had not noticed as I also do a text replace from . to _ and thought it was all correct. Even when debugging I did not see it, often we cannot see the obvious which is why a second opinion of those wiser than me is always good.
The working code is now as follows.
private void cmbobx_version_SelectedIndexChanged(object sender, EventArgs e)
{
Type t = this.GetType(); //need to get the type
MethodInfo method = t.GetMethod("Getinfo_" + cmbobx_version.Text.Replace('.', '_')); //put together function name
method.Invoke(this, new object[] {Fridge, "Order" }); //call function with parameters
}
Please do be careful as the functions will have no references but it will compile and will work. It all works at run-time when you call the correct function.
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
I have a Combobox with many choices. What the user chooses takes them to a case statement. In this case one of the items that gets choosen is a string. Now this string I want to use to take start a specific function thread. e.g. I have function
public void DoWorkAP(){}
and another
public void DoWorkAG(){}
From the Combo box the user makes a choice and the case statemtn will have a string called sWhichWork and that is set to either "DoWorkAG" or "DoWorkAP"
Now in the UI code I have a thread
Thread t = null;
And when a button is pressed a function is called and in this function I have
t = new Thread(sWhichWork);
t.Start();
This seemed good as I woudl exect sWhichWork to be substituted with "DoWorkAG" or "DoWorkAP" but instead I get
"cannot convert from 'string' to System.Threading.ParameterizedThreadStart' "
Now I take out the SWhichWorks and have the following
t = new Thread(DoWorkAG);
t.Start();
This is good as it compiles and takes me to the correct place. So the question is how can I have a variable string choosen from the combox to the case stament take me to the same place?
If you have only two options, I'd go for
t = new Thread(sWhichWork == "DoWorkAG" ? DoWorkAG : DoWorkAP);
This would work as well:
t = new Thread(this.getType().GetMethod(sWhichWork).Invoke(this, new object[]));
You just switch on the thread:
var action = myComboBox.Text;
new Thread(() => {
if (action == "1") F1();
else F2();
});
Super simple.
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.
I'm not sure if my title is really correct. I've looked around and searched but not found anything so please forgive me if my problem has been answered already.
What I would like to do is call a function but not have to come back to the calling line of code. e.g
public static void temp(obj) {
switch (obj.id) {
case "1" :
if(blah) {
obj.id = "2";
temp(obj);
}
break;
case "2" :
obj.response = "done";
break;
}
}
so basically I dont want to eventually come back to my temp(obj) in the first case and fully pass control. Does this make sense, is it even possible and my architecture is all wrong?
Thank you for your time.
Let me see if I understand the question:
You've got a function Foo(), which calls function Bar(). (I wanted to remove the recursion you had in your example for simplicity, please correct me if that was important.) When function Bar() returns, you want control to pass not back to Foo(), but to Foo's caller?
This is probably possible in lower-level languages, like C, by hacking the stack and not placing Foo()'s return address there, so that when Bar() tried to return, it would jump to Foo's caller instead.
However, in C#, no. The call stack is a stack, and control will pass back in order. The only thing you can do would be to put a return statement after each call to Bar().
Edit:
"recursive calls without them being recursive"
How about this:
bool doItAgain = true;
while(doItAgain)
{
doItAgain = false;
// process, with your switch statement or whatever.
if(...)
{
doItAgain = true;
continue; // if necessary, skip any code after this statement. May not be necessary if you have things set up right.
}
}
If this were C++, you could eliminate the break and let the case "1" fall through, but this is not allowed in C# switch statements.
public static void temp(obj) {
if (obj.id == "1") {
obj.id = "2";
temp(obj);
}
if (obj.id == "2")
obj.response = "done";
}
Do you need the recursive call? This code retains your recursive call and sets obj.response to "done" after changing obj.id to "2". However, obj.response is set twice because of the recursive call. What are you trying to do?
I'm not sure what you exactly intend, but it sounds like a callback to me. Here is one possible example:
void DoSome()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(delegate { RunMe(); ReturnTo(); }));
}
void RunMe() { }
void ReturnTo() { }
You start in DoSome() and continue, when RunMe is finished ReturnMe is called.