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.
Related
I want to make a function for Windows Forms like:
private void do(textBox_name, string text)
{
textBox_name.Text=text.toString();
}
The function should take name of textBox as an argument, then write text to right textBox.
But I don't know how can I send properly which textBox should be used.
At this moment I have done it in "if statement", but adding new elements is scripting it again and again because I have to write
textBox1.Text=text.toString(); then textBox2.Text=text.toString();
for every textBox that takes a lot of time. Also, I know I can do it with switches, like this:
switch(ID)
case 1:
textBox1.Text=text.toString();
break;
case 2:
textBox2.Text=text.toString();
But I guess there is a way to do one function for every textBox.
I have one question - why are you invoking ToString() method on a string? It is completely unnecessary.
Your function should look like:
private void do(TextBox tb, string text)
{
tb.Text = text;
}
If you work with doubles, then it will differ slightly:
private void do(TextBox tb, double number) //use meaningful names, "text" for double is poor choice
{
tb.Text = number.ToString();
}
Welcome again. Problem has been solved, it was easy so i'm really embarassed how long i was looking for solving problem. I didn't knew that i can send to function parameter of TextBox.
Now it looks like
private void write(TextBox tbox, string text)
{
tbox.Text=text;
}
I am creating a my account page for my C# application. I have it setup with loads of different edit buttons for different details, i was to make it less tedious to produce and create 1 method which will change the form to the way it is needed.
Here is my code which i hope will stop the code re-use.
private void OnEditButton(string boxSelected, Size size)
{
if (doneBtn.Visible)
{
MessageBox.Show("Must edit current detail before editting a new one");
return;
}
lnametxt.Enabled = true;
lnameLink.Visible = false;
doneBtn.Visible = true;
doneBtn.Location = new Point(size);
TextBoxSelected = boxSelected;
}
The TextBoxSelected Property tells the database which column they will be changing, so this is a parameter as it will change for each edit link.
What am i trying to do? - I am trying to pass the Size as a parameter to this method. Here is the code that will call the method.
private void lnameLink_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
OnEditButton("lname", (495, 55));
}
at "(495, 55)" it has an error i have put the second lots of brackets to try and see if it will work with that there instead of having it on its own. Both show it has 3 parameters.
Here is the idea i am trying to go for, but without the parameters in place:
private void OnEditButton()
{
if (doneBtn.Visible)
{
MessageBox.Show("Must edit current detail before editting a new one");
return;
}
lnametxt.Enabled = true;
lnameLink.Visible = false;
doneBtn.Visible = true;
doneBtn.Location = new Point(495, 55);
TextBoxSelected = "lname";
}
if you would like any more information then please let me know and i will add it. Thank you in advance
the function OnEditButton takes two parameters, a string boxSelected and an object size of type Size.
So when you call it you have to do
OnEditButton("lname", new Size(495.0, 55.0));
You have to pass an instance of the type Size
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));
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.
What is the best / good way to implement method calls.
For eg: From the below which is generally considered as best practice. If both are bad, then what is considered as best practice.
Option 1 :
private void BtnPostUpdate_Click(object sender, EventArgs e)
{
getValue();
}
private void getValue()
{
String FileName = TbxFileName.Text;
int PageNo = Convert.ToInt32(TbxPageNo.Text);
// get value from Business Layer
DataTable l_dtbl = m_BLL.getValue(FileName, PageNo);
if (l_dtbl.Rows.Count == 1)
{
TbxValue.Text = Convert.ToInt32(l_dtbl.Rows[0]["Value"]);
}
else
{
TbxValue.Text = 0;
}
}
Option 2 :
private void BtnPostUpdate_Click(object sender, EventArgs e)
{
String FileName = TbxFileName.Text;
int PageNo = Convert.ToInt32(TbxPageNo.Text);
int Value = getValue(FileName, PageNo);
TbxValue.Text = Value.ToString();
}
private int getValue(string FileName, int PageNo)
{
// get value from Business Layer
DataTable l_dtbl = m_BLL.getValue(FileName, PageNo);
if (l_dtbl.Rows.Count == 1)
{
return Convert.ToInt32(l_dtbl.Rows[0]["Value"]);
}
return 0;
}
I understand we can pass parameters directly without assigning to a local variable... My question is more about the method definition and the way it is handled.
If you're subscribing to the event automatically, I don't think it's particularly bad to have a method with the event handler signature which just delegates to a method which has the "real" signature you need (in this case, no parameters).
If you're subscribing manually, you can use a lambda expression instead:
postUpdateButton.Click += (sender, args) => PostUpdate();
and then do the work in PostUpdate. Whether you then split up the PostUpdate into two methods, one to deal with the UI interaction and one to deal with the BLL interaction is up to you. In this case I don't think it matters too much.
How you structure UI logic to make it testable is a whole different matter though. I've recently become a fan of the MVVM pattern, but I don't know how applicable that would be to your particular scenario (it's really designed around Silverlight and WPF).
A couple of other comments though:
Conventionally, parameters should be camelCased, not PascalCased
Do you genuinely believe you're getting benefit from prefixing local variables with l_? Isn't it obvious that they're local? Personally I'm not keen on most of the variable names shown here - consider naming variables after their meaning rather than their type.
Using a DataTable to return information is a somewhat error-prone way of doing things. Why can the BLL not return an int? to indicate the value (or a lack of value)?
here is what i like to to if i don't implement mvc. and i'm assuming web here.
I'd do option 2 first but instead of having the buttons code set the text id create a property to set the text boxs value.
I do this because if something else sets the textbox value then you are going to duplicate code. bad if you change a name or control type.
According to your example, option 2 is the way to go. Option 1 knows about your form and how to display data on it, which violates the SRP.