So I'm at a client's site and we're discussing adding a new method to an existing class. One of the client's programmers said, "We should put the method in the base class and let all the derived classes inherit it from it" Another programmer said, "I think it would be better to create a new class that inherits from our base class and add the new method to it."
And I said, "Let's not change anything. Let's just create the new method."
I had a couple of reasons for disliking the first two suggestions. First, of course they weren't my suggestions. But beyond that, I didn't want to change the base class because the base class had this neat feature: it worked. I hate making changes to working code—it's just asking for something new to fail. Adding a new derived class would avoid that problem, but creates a new one: developers would have to be told to use the new class in order to get access to the new method. Developers were already using the existing classes and I didn't see any value in making them change.
So I suggested we create an extension method and avoid all those problems. An extension method sits in a separate file from the base class, so the base class is unchanged (though the method would be in the same Class Library project and be distributed as part of the same DLL). An extension method also appears automatically in the IntelliSense dropdown lists for the existing classes, so developers would have it presented to them as part of the classes they were already using.
Creating an extension method is easy. In C#, you add a static class with a static method, with both the class and method declared as public. The method's first parameter specifies the class the method will attach itself to (the parameter has to be flagged with the this keyword).
When the extension method is used from an object, that object is automatically passed to the extension method in that parameter. This ToggleCustomerStatus method, for instance, will appear in the IntelliSense list of any Customer object (or any object that inherits from Customer), toggle the value of the Status property on the Customer object the method is used on, and return the new value:
public static class CustomerCSExtensions
{
public static bool ToggleCustomerStatus(this Customer cust)
{
cust.Status = !cust.Status;
return cust.Status;
}
}
To create an extension method in Visual Basic, add a Module, declare it Public, write your function or subroutine, and decorate the method with the extension method. The first method parameter specifies the class to which the method will be added. When the extension method is used from an object, that object is automatically passed to the extension method in that parameter.
This ToggleCustomerStatus method, for instance, will appear in the IntelliSense list of any Customer object (or any object that inherits from Customer) and, unlike my previous example, doesn't return a value:
Public Module CustomerExtensions
<System.Runtime.CompilerServices.Extension()>
Public Sub ToggleCustomerStatus(ByVal cust As Customer)
cust.Status = Not cust.Status
End Sub
End Module
To use the extension method, you need to add an Imports or using statement for the namespace that the extension was declared in. If the extension method is in the same namespace as the object it's attaching itself to, developers using that object will probably already have that namespace in place. After that, using an extension method looks just like using any other method (and it doesn't matter if the class the extension method is being attached to is written in one language and the extension method itself is written in another language). Here's the C# ToggleCustomerStatus method in action in some VB code:
Dim cust As Customer
If cust.ToggleCustomerStatus Then …
And the VB version used from C# code:
Customer cust;
cust.ToggleCustomerStatus();
While my sample extension method accepts only the single parameter that specifies which class it should attach itself to, an extension method can accept multiple parameters, just like any other method. You can also specify an interface as the first parameter's datatype so that your extension method will attach itself to a variety of objects (provided they all implement that interface). And, most importantly, you don't change any working code.
Posted by Peter Vogel on 12/03/20122 comments
It's hard to create memory leaks in .NET, but I can do it when developing in SharePoint without even trying very hard. The SharePoint Dispose Check (SPDisposeCheck to its friends) analyzes your code to see if you're following Microsoft's best practices in disposing of SharePoint resources.
SPDisposeCheck is a Visual Studio Add-In that adds a new menu item to your Tools menu. When you select it, SPDisposeCheck pops up a dialog that lets you check which parts of your Solution will be checked. In addition to running an analysis when you want, you can also choose to have your code analyzed as part of building your projects. By default, the results are displayed in the Output Window (you have to set the dropdown list at the top of the Window to SPDispose check). However, you can also choose to have any problems listed as Errors.
PDisposeCheck won't stop you from having memory leaks in SharePoint; but at least when you track a leak down, it won't be something so obvious that you'll feel foolish about it.
Posted by Peter Vogel on 11/29/20120 comments
Scattered across all the services I've created, I must have 257 methods whose names begin with the word "Get" (e.g., GetCustomerData, GetOrdersForDate). And I typically have a corresponding method for accepting the data (e.g., UpdateCustomerData, SetOrders). I wouldn't write a class like that with two separate methods; I'd create a Property just called, for instance, CustomerData.
It turns out that you can use properties in a WCF Service: just put the OperationContract attributes on the property's getter and setter:
Public Property CustomerData As String
<OperationContract()> _
Get
Return _CustData
End Get
<OperationContract()> _
Set(value As String)
_CustData = value
End Set
End Property
Now, when I add a service reference to a consumer to generate the client-side proxy, I discover that I've only solved half of my problem. For the example above, the client-side proxy has two methods: get_CustomerData and set_CustomerData:
Dim cr As New CustomerService.CustomerServiceClient
sr.set_Data(custData)
Dim custData As CustomerData = sr.get_Data()
But on the service side, I no longer have two separate methods. Instead, the getter and setter for my data are now brought together in one Property. I'm OK with that.
If you're feeling very radical, you can write your property so that it accepts a parameter:
Public Property CustomerData(CustomerID As String) As String
<OperationContract()> _
Get
Return _CustData
End Get
<OperationContract()> _
Set(value As String)
_CustData = value
End Set
End Property
On the client-side, the proxy's get_ and set_ methods will now require a parameter:
Dim cr As New CustomerService.CustomerServiceClient
sr.set_Data("ALFKI", custData)
Dim custData As CustomerData = sr.get_Data("ALFKI")
Posted by Peter Vogel on 11/26/20120 comments
I'm not sure whether to classify this as a tip or bad advice: It's possible to redefine the operators (e.g. !, =, ++) used with a class. That doesn't mean it's a good idea. As I discussed in an earlier tip, the differences in using equality tests between C# and VB (and, within a language, the differences between the equals operator and the Equals method) probably create enough confusion without you assigning an arbitrary meaning to =/== for a particular class. But having said that…
Let's say you have some class that switches between two states: A Customer class that can be creditworthy or not creditworthy; a Service that switches between being "in" or "out" of service; a Product that is in-stock or out-of-stock. You can have a property that allows you to control this:
Dim cust As New Customer("A123")
cust.Creditworthy = False
To toggle between the two states, you could use this code:
cust.CreditWorthy = Not cust.Creditworthy
But it might be nice to just do this to toggle the Creditworthy property:
cust = Not cust
Before showing how to implement this, let me point out my chief objection: How would anyone reading your code or using your Customer object know what the Not operator is doing?
But if you want to do it, you add a shared/static Operator method to your class with the name Not. This Operator method should accept and return the object that it's part of (if you wanted to redefine the + operator, you'd add an Operator method called +). That method will be passed the object that the operator is being used on so that you can modify the object if you wish. Implementing my state-switching code would look like this:
Public Shared Operator Not(Cust As Customer) As Customer
Cust.Creditworthy = Not Cust.Creditworthy
Return Cust
End Function
In C#, the code looks like this:
public static Customer operator !(Customer cust)
{
cust.Creditworthy = !cust.Creditworthy
return cust;
}
I can now toggle the creditworthiness of a Customer object in C# like this:
cust2 = !cust;
Postfix and prefix conventions are also honored with operators that support it. The primary difference in overriding binary operators (e.g. +, -) is that your operator method is passed two parameters: the object on either side of the operator.
Like I said: I'm not sure if this is a tip or bad advice, but I had a client ask me how to do it so people do seem to care.
Posted by Peter Vogel on 10/16/20121 comments
Entity Framework gets all the attention, but there's still something to like about ADO.NET DataSets. For instance, one reason that typed DataSets remain popular is that you can dramatically simplify your code by extending the DataSet with your own custom TableAdapter methods. All you have to be able to do is create an SQL statement in the Visual Studio query designer: Visual Studio will generate the code for you.
Ordinarily, to fill a table in a DataSet you need a half-dozen lines to open a connection, create an adapter (with its commands and parameters), set values in the adapter's parameters, call the adapter's Fill method, and then retrieve the resulting table (without, of course, forgetting to close the connection).
Update, insert, and delete statements aren't any simpler. What's especially irritating is that the code is virtually identical from one retrieval/update to another: really, only the SQL statement changes. With a custom TableAdapter method, though, you just call a method, passing the values required by your SQL statement.
When you create a typed DataSet, you get a TableAdapter with two methods on it for each table you drag into the DataSet: You get a Fill method that loads data into a DataTable but doesn't return anything, and a GetData method that fills the DataTable and then returns the DataTable to the calling code. As an example, here's the GetData method in action, retrieving all the rows in Northwind database's Orders table into a DataTable in a DataSet and then returning the DataTable:
Dim nwTB As New Northwind.OrdersDataTable
Dim nwtba As New NorthwindTableAdapters.OrdersTableAdapter
nwTB = nwtba.GetData
To create your own GetData, Fill, or update method, first right-mouse click on your table in the TableAdapters area at the bottom of the table and pick Add Query. That will bring up the query wizard where you can choose between using an SQL statement to retrieve your data, select from existing stored procedures, or create your own stored procedure.
Assuming you select Use SQL Statements, you'll be taken to a page that allows you to select the kind of SQL statement you want (everything from Select to Insert statements). After that choice, you'll be shown a default SQL statement you can modify. If you're not confident about your SQL writing skills, click the Query Builder button at the bottom of the dialog to be taken to Visual Studio's form-based query builder.
Once you've finished writing your SQL statement, the wizard will take care of writing all the ADO.NET code for you—all you have to do is name the method that will be added to your TableAdapter. For SQL statements, the wizard even generates a Fill and a GetData method. So to call a SQL statement that fills a DataTable with orders for a particular customer and hands the DataTable back to you, you just need this code:
Dim nwTB As New Northwind.OrdersDataTable
Dim nwtba As New NorthwindTableAdapters.OrdersTableAdapter
nwTB = nwtba.GetDataByCustomerID("ALFKI")
If you're paid by the hour, feel free to write the ADO.NET code. But this is the best kind of code-generation solution, because it allows you to concentrate on the one part of the code that matters -- the SQL statement -- while the boilerplate code is taken care of for you.
Posted by Peter Vogel on 10/09/20120 comments
It's not unusual to include a link in your page with a URL that points to a PDF file to let your users view the file on their computer. However, you can also control, through the URL, where and how the PDF file is displayed: just add a hash/pound sign (#) and some parameters to the PDF's URL.
For instance, the page parameter lets you open the PDF file at a specific page. This example opens the file at page 3:
http://mysite.com/userguide.pdf#page=3
You can also set up a search term for the user and position the view on the first appearance of the term (with the term highlighted) using the search parameter. This example searches for the word "test":
http://mysite.com/userguide.pdf#search=test
You're not limited to just positioning the user in the document. You can also specify how the document is to be displayed by using the view parameter. You can also combine parameters using the ampersand (&). This example repeats the search from the previous example but also fits the whole page into the view:
http://mysite.com/userguide.pdf#search=test&view=fit
Additional parameters let you turn on (or off) toolbars, panes, and draw highlight boxes around arbitrary text. Adobe has a document (in PDF, of course) describing all of the options.
Thanks to Larry Raby for letting me in on this!
Posted by Peter Vogel on 10/03/20120 comments
A reader responded to an earlier tip on Visual Studio keyboard shortcuts by recommending VsVim, by Jared Parker. If the idea of never taking your fingers off the home row of your keyboard again, never having to use a menu, and never, ever reaching for the mouse sounds like heaven to you, then Jared's right: you should be looking at VsVim.
If using the letter d to delete, using uppercase D to delete to end of line, and using dd to delete a whole line is something you'll remember, then you're probably a veteran Unix programmer. In that case, you'll find the Visual Studio focus on WIMP (Windows, Icons, Menus, Pointer), well, wimpy. VsVim will put you back in control.
If you're as old as me, you remember vi as the world's most powerful keyboard editor -- the populariser (if not the inventor) of the Ctrl-Alt-Shift-meta-Coke-Bottle keyboard shortcut combination. You could do anything with vi if you knew the right keyboard combination. I've never been a keyboard-oriented person, but even I grew to have a nagging affection for the power of vi's keystroke combinations -- and my co-workers who were keyboard oriented loved what they could do with vi without taking their hands off the home row keyboard.
Vi gave birth to vim (vi iMproved), which added mouse support and even more editing commands. Now there's VsVim, which delivers vim functionality as a Visual Studio add-in. You can get VsVim from the Visual Studio Gallery site, or through Extension Manager from within Visual Studio.
It's an excellent package: reliable, quick, and it doesn't seem to fight with other add-ins (I used it with ReSharper installed, for instance). It's not overbearing in re-assigning your keys, so while you'll pick up lots of new keyboard commands, you shouldn't lose any of the ones you're used to. From the time I spent playing with it, it looks like a great tool for the keyboard oriented (and a free one).
However, VsVim is also a single-developer project and you might be more comfortable with a product that has a whole company behind it. If so, you should check out
ViEmu. ViEmu adds more vi-related features and also works in Outlook and SQL Server (but costs actual money).
Posted by Peter Vogel on 09/25/20120 comments
Do you get tired of scrolling through the New Project Item lists to get to the item templates that you need, while skipping the ones that you'll never use? The same is probably true, though to a lesser extent, with the New Project dialog.
Why not slim those lists down to the half-dozen items you actually use that will, as a result, be right there when you need them? This probably goes against the grain of most developers' attitude towards new technology, but let's face it: you (and your organization) have probably figured out which templates you are and aren't going to use in Visual Studio.
The templates in the New Project and New Item dialogs are zip files kept in the C:\Program Files\Microsoft Visual Studio versionNumber\Common7\IDE\ItemOrProjectTemplates\language folder (this does vary from one installation to another. Just keep looking -- they're in there somewhere). Before you delete the templates you don't want, copy the folder to someplace safe so that you can get back the templates you've deleted if you ever need them (and drop a text file in the folder to remind yourself where you put the original templates). Then clean house.
When you're done, make sure Visual Studio isn't running and, from the Visual Studio Command prompt, have Visual Studio rebuild its lists with this command:
devnv.com /installvstemplates
NEVER INTERRUPT THIS COMMMAND. Wait patiently for it to finish. When you start Visual Studio next you'll have all (and only) the templates you use.
Posted by Peter Vogel on 08/23/20122 comments
I was recently asked by a WPF programmer how to modify a value passed between bound properties in a XAML file. You can't, for instance, integrate math into a binding expression, as this example does, to divide the value returned by 2:
<Image Height="100" Width="100" Name="MyImage" Source="Me.jpg"
Opacity="{Binding ElementName=MySlider, Path=Value/2}" /&rt;
This doesn't work, either:
<Image Height="225" Width="300" Name="CurrentImage" Source="Me.jpg"
Opacity="{Binding ElementName=MySlider, Path=Value}/2" /&rt;
While XAML gives you a lot of options when binding a property on one control to something else, modifying the data isn't allowed; at least, not directly. The answer is to use a custom converter. Programmers usually create converters to handle converting the data type of one property to the data type to another property (though XAML will handle a lot of conversions -- numerics to strings, for instance --on its own). But you can also use converters to massage the data in any way you want. This example, for instance, binds the Opacity setting for an Image control to the value in a slider control:
<Slider Margin="10" Name="MySlider" Minimum="0.0"
Maximum="2" Value="0.5"/&rt;
<Image Height="100" Width="100" Name="MyImage" Source="Me.jpg"
Opacity="{Binding ElementName=MySlider, Path=Value}" /&rt;
Let's say that you want the transparency to be one-half of the value in the Slider: a converter will solve the problem. This converter, for instance, divides the number passed to it by 2 in its Convert method:
[ValueConversion(typeof(int), typeof(int))]
public class Divider : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
return object/2;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
return object * 2;
}
}
You need to do three things to use your converter. First, define a namespace for your converter (I've assumed that the converter is in the same project as the XAML file and the namespace for the project is MyApp):
<Window x:Class="MyClass"
…
xmlns:current="clr-namespace:MyApp"&rt;
Then you have to add your converter to your resources. I'm adding this converter to the Window's resources with the key MyDivider:
<Window.Resources&rt;
<current:Divider x:Key="MyDivider"/&rt;
</Window.Resources&rt;
Finally, invoke your converter by passing the resource's key to the StaticResource object's constructor to retrieve it from the resources collection, and then passing that result to the Binding object's Converter property, like this:
<Image Height="100" Width="100" Name="MyImage" Source="Me.jpg"
Opacity="{Binding ElementName=MySlider, Path=Value
Converter={StaticResource MyDivider}}
Posted by Peter Vogel on 08/09/20123 comments
Probably the most popular tip has been in this column has been the one on four Visual Studio keyboard shortcuts. But if you want, you can create your own shortcuts for any Visual Studio commands you use a lot. Of course, most commands are already assigned to keyboard shortcuts, but this feature also lets you define a command to some key combination you'll actually remember.
To create your own shortcut, go to Tools | Options | Environment | Keyboard. From the listbox in the middle of the resulting dialog, select the Visual Studio command to which you want to tie your keyboard shortcut (there are lots of commands, so the search function that's provided can be helpful here). Then click in the Press shortcut keys textbox and press the key combination you want to use for the command. Click the OK button and you've created your own shortcut.
Posted by Peter Vogel on 07/29/20122 comments
In an earlier column I discussed using the Register and Resolve methods with Microsoft's Unity dependency container. However, if you've got all of Visual Studio's hotfixes applied, you'll have access to some overloaded and generic versions of those methods. For instance, for the Resolve method, I used this version:
res = cont.Resolve(typeof(ICustListVM),"DefaultCustListVM");
The generic version moves the first parameter (the type of class you're looking for) into the generic:
res = cont.Resolve<ICustListVM>("DefaultCustListVM");
In addition to saving you some typing, it can also save you some type casting. The non-generic version of the Resolve method always returns type object, but the generic version returns the type specified in the generic.
There are also several overloads for the Register method, so you don't have to pass as many parameters as I used in the article. In the article, I used this wordy version:
ContainerControlledLifetimeManager cclm =
new ContainerControlledLifetimeManager();
cont.RegisterType(typeof(ICustListVM),
typeof(CustListVM), "DefaultCustListVM", cclm);
With the hotfixes installed, you can just use this:
cont.RegisterType(typeof(ICustListVM),"DefaultCustListVM");
And, if you use the generic version, you can get away with as little as this:
cont.RegisterType<ICustListVM>("DefaultCustListVM");
Posted by Peter Vogel on 07/17/20120 comments
Up until a few weeks ago, the only way I knew of to get back to an old command in the Command Prompt was to press the Up arrow and walk back through the commands. It turns out that if you press F7 in the Command Prompt, a window pops up showing all the commands you've executed, and you can cycle through them with the Up or Down arrows (you can't edit the commands, though).
Speaking of editing commands: The most common error I make when entering commands is misspelling file or folder names. It turns out that I don't have to type in a full file name in the Command Prompt. If I type my command, followed by the first letters of the file or folder name I want and just keep hitting the Tab key, I'll cycle through all the file and folder names in the directory. I can even use wildcard characters (e.g. c*.DLL to find all the DLLs with names beginning with the letter C) with this trick.
And did you know that if you click on the icon in the left-hand corner of the Command Prompt title bar and select the Edit choice, you can cut, copy and paste in the Command Prompt?
Posted by Peter Vogel on 07/08/20125 comments