KeyLimeTie Blog
Writing constructors is often a repetitive task. Many developers write the first constructor and then copy and paste the code into another constrcutor to satisfy the multiple overrides defined in the class interface. Here's an example:
1public class Menu
2{
3 //private variables
4 private string mstrName;
5 private string[] marrItems;
6
7 public Menu() : this("", 0)
8 {
9 }
10
11 public Menu(int intNumItems) : this("", intNumItems)
12 {
13 }
14
15 public Menu(string strName, int intNumItems)
16 {
17 marrItems = (intNumItems > 0) ? new string[intNumItems] : null;
18 mstrName = strName;
19 }
20} This is not a good idea. A better approach is constrcutor chaining where you create a common method to do the initializing. Here's a better approach:
1public class Menu
2{
3 //private variables
4 private string mstrName;
5 private string[] marrItems;
6
7 public Menu()
8 {
9 MenuConstructor("", 0);
10 }
11
12 public Menu(int intNumItems)
13 {
14 MenuConstructor("", intNumItems);
15 }
16
17 public Menu(string strName, int intNumItems)
18 {
19 MenuConstructor(strName, intNumItems);
20 }
21
22 private void MenuConstructor(string strName, int intNumItems)
23 {
24 marrItems = (intNumItems > 0) ? new string[intNumItems] : null;
25 mstrName = strName;
26 }
27}The second approach generates far more efficient code. In the first example, the compiler adds code to perform several functions on your behalf in constructors. It adds statements for all variable initializers and calls the base class constructor...this is a very big difference! Also consider readonly constants. By nature, they can only be set in the constructor. By centralizing this action, we avoid more redundancy.
These are just a few reasons why...to read more, pick up "Effective C#: 50 Specific Ways to Improve Your C#" by Bill Wagner.
You can buy it at the Addison-Wesley website:
http://www.aw-bc.com/
When a web page has multiple buttons, you might want to change the default button in different cases. For example, imagine a web page that has a search area with datagrid results. The search area allows you to filter your search. When a result is selected to be edited, the fields that can be edited and a 'Save' button are displayed. If the 'Search' button is the default button, think about what happens when someone edits an item and hits 'Enter' while in an edit control field...'Search' is submitted, not 'Save'. Now you have to redo your changes and click 'Save'.
A lot of people post the following solution:
Page.RegisterHiddenField("__EVENTTARGET", "cmdSave") For some reason, this doesn't always work. Even when 'cmdSave' is set a the '__EVENTTARGET', the page is submitted but the button's event isn't fired.
To resolve this, we need to submit the form ourselves. The following snippet of code shows how to assign submit buttons to controls (TextBoxes, DropDownLists, etc.). Once you implement the main method into your page's base class, it's only one line of code per control to set the default button.
1. Enum of Control Types - This enumeration lists the control types you can set a default button for. Add more as needed.
1public enum ControlTypes
2{
3 None = 0,
4 TextBox = 1,
5 DropDownList = 2,
6 CheckBox = 3,
7 ListBox = 4
8}2. Method in Base Class to associate control to button 1public void SetDefaultButtonForControl(System.Web.UI.Page objPage,
2 Enums.ControlTypes intControlType, object objControl,
3 System.Web.UI.WebControls.Button objButton)
4{
5 string strScript = @"<SCRIPT language=""javascript"">
6 <!--
7 function catchKeyDown(btn, event)
8 {
9 if (document.all)
10 {
11 if (event.keyCode == 13)
12 {
13 event.returnValue=false;
14 event.cancel = true;
15 btn.click();
16 }
17 }
18 else if (document.getElementById)
19 {
20 if (event.which == 13)
21 {
22 event.returnValue=false;
23 event.cancel = true;
24 btn.click();
25 }
26 }
27 else if(document.layers)
28 {
29 if(event.which == 13)
30 {
31 event.returnValue=false;
32 event.cancel = true;
33 btn.click();
34 }
35 }
36 }
37 // -->
38 </SCRIPT>";
39 objPage.RegisterStartupScript("DefaultButtonForControl", strScript);
40
41 //Register with the control
42 switch (intControlType)
43 {
44 case Enums.ControlTypes.TextBox:
45 {
46 TextBox objTextBox = objControl as TextBox;
47 objTextBox.Attributes.Add("onkeydown",
"catchKeyDown(" + objButton.ClientID + ",event)");
48 break;
49 }
50 case Enums.ControlTypes.DropDownList:
51 {
52 DropDownList objDropDownList = objControl as DropDownList;
53 objDropDownList.Attributes.Add("onkeydown",
"catchKeyDown(" + objButton.ClientID + ",event)");
54 break;
55 }
56 case Enums.ControlTypes.ListBox:
57 {
58 ListBox objListBox = objControl as ListBox;
59 objListBox.Attributes.Add("onkeydown",
"catchKeyDown(" + objButton.ClientID + ",event)");
60 break;
61 }
62 case Enums.ControlTypes.CheckBox:
63 {
64 CheckBox objCheckBox = objControl as CheckBox;
65 objCheckBox.Attributes.Add("onkeydown",
"catchKeyDown(" + objButton.ClientID + ",event)");
66 break;
67 }
68 }
69}3. Implementation in webpage - This example sets the 'cmdSearch' button as the default button for the txtSearchLastName, cboSearchDistrict and cboSearchRole search controls. It also sets the 'cmdSave' button as the default button for the 'txtNewQ1', 'txtNewQ2', 'txtNewQ3', 'txtNewQ4' and 'txtComments' edit controls.
1private void Page_Load(object sender, System.EventArgs e)
2{
3 if (!Page.IsPostBack)
4 {
5 SetDefaultButtonForControl(this,
6 Enums.ControlTypes.TextBox, txtSearchLastName, cmdSearch);
7 SetDefaultButtonForControl(this,
8 Enums.ControlTypes.DropDownList, cboSearchDistrict, cmdSearch);
9 SetDefaultButtonForControl(this,
10 Enums.ControlTypes.DropDownList, cboSearchRole, cmdSearch);
11 SetDefaultButtonForControl(this,
12 Enums.ControlTypes.TextBox, txtNewQ1, cmdSave);
13 SetDefaultButtonForControl(this,
14 Enums.ControlTypes.TextBox, txtNewQ2, cmdSave);
15 SetDefaultButtonForControl(this,
16 Enums.ControlTypes.TextBox, txtNewQ3, cmdSave);
17 SetDefaultButtonForControl(this,
18 Enums.ControlTypes.TextBox, txtNewQ4, cmdSave);
19 SetDefaultButtonForControl(this,
20 Enums.ControlTypes.TextBox, txtComments, cmdSave);
21 }
22}
The C# foreach statement generates the best iteration code for any collection you have. Examine these three loops:
int[] foo = new int[100]
//Loop 1
foreach (int i in foo)
Console.Write(i.ToString());
//Loop 2
for (int i = 0; i < foo.Length; i++)
Console.Write(i.ToString());
//Loop 3
int i = foo.Length;
for (int j = 0; j < i; j++)
Console.Write(foo[j].ToString());
For the current and future C# compilers (version 1.1 and up), loop 1 is the best. It's even less typing so productivity is also better. Note: The C# 1.0 compiler produced much slower code for loop 1, so loop 2 is the best in that version. By moving the "Length" variable out of the loop, you make a change that hinders the JIT compler's chance to remove range checking inside the loop.
Loop 3 is the worst...the CLR guarantees that you cannot write code that overruns the memory your variables own. The runtime generates a test of the actual array bounds (not the "i" variable) before accessing each particular array element. You are now forcing the runtime to check the array index on every loop!
Loop 1 is better than Loop 2 because you allow the compiler to check the upper and lower bounds. Some people still believe index variables start at 1, not 0. Loop 2 forces you to know the lower bound, whereas Loop 1 does the work for you.
Custom objects/types: foreach allows you and your users to iterate across members if you support the .NET environment's rules for a collection.
These are just a few reasons why...to read more, pick up "Effective C#: 50 Specific Ways to Improve Your C#" by Bill Wagner.
You can buy it at the Addison-Wesley website:
http://www.aw-bc.com/
If you're still creating public variables in your types, stop now. You should be using properties as they enable you to create an interface that acts like data access, but still has all of the benefits of a method. They also provide encapsulation, something you want as an object-oriented developer.
The .NET Framework assumes you'll use properties for your public data members. The data binding code classes support properties but do not support public data members. For example:
txtLastName.DataBindings.Add("Text", Employee, "LastName");
This example bind the Text property of "txtLastName" TextBox control to the "LastName" property of the "Employee" object.
As you already know, properties allow you to apply rules as to what data can be applied to your private variables. Properties allow you to apply those rules in one location...much easier to update in the future.
These are just a few reasons why...to read more, pick up "Effective C#: 50 Specific Ways to Improve Your C#" by Bill Wagner.
You can buy it at the Addison-Wesley website:
http://www.aw-bc.com/