Robert Westerlund

A developer's blog on code, technology and tools in the Web, .NET and other development areas.

NAVIGATION - SEARCH

"GetMemberName" or "getting rid of (some) magic strings"

Earlier today I had another discussion() with a co-worker of mine. This discussion related to magic strings and potential ways to get rid of them. I have previously mentioned that I dislike magic strings, but I haven't mentioned why. Nor have I mentioned in which circumstances which I dislike seeing them.

When do I use magic strings

There are cases where magic strings are pretty useful. An example of this is in communicating between different applications, where strings are more descriptive than using, for example, an integer. Thus, if I send a message from application A to application B telling it to do “<action>print</action>” on something, it is a lot more descriptive and easy to debug than if it would be “<action>3</action>”. The same goes for the code listening to this message.

switch(action)
{
    case “print”:
        //Do the printing
        break;
}

it is a lot better than

switch(action)
{
    case 3:
        //Do the printing
        break;
}

However, I often try to limit the risk of errors, when using magic strings, for example by creating an XSD forcing an enumeration constraint (only allowing the content of the action element to be one of a limited set of values). This also has the benefit of making the message easier to use. (Whether it could still be called a magic string after enforcing an enumeration constraint on the value is a question of definitions, so in general I try to avoid the pitfalls of magic strings.)

When do I try to avoid magic strings

On the other hand, there are a lot of cases where I believe that magic strings are nothing but evil (although in some cases they may be necessary evil). One example of this is the INotifyPropertyChanged interface. Another such example is throwing ArgumentNullExceptions.

public class MyClass:INotifyPropertyChanged
{
    public MyClass(IRepository repository)    
    {
        if (repository == null)
        throw new ArgumentNullException(“repository”);
    }

    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            OnNotifyPropertyChanged(“Name”);
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
    }
}

What happens when we change the IRepository to be a IDataRepository and therefore also renames the constructor parameter to dataRepository? What happens when we rename the Name property to Title? Well, in most cases we will remember to change the string as well, but every now and then we will forget to change the string. Also, sometimes we will misspell the property name, e.g. writing -“Neme” instead of “Name”. Of course, I could unit test all the property setters to make sure that the NotifyPropertyChanged is fired with the correct propertyName. While this might be a good (or bad) idea in and of itself, we still would have to remember to change the contents of the string in the unit test when we rename the property.

Expressions to the rescue

With C# 3.0 we got lambda expressions, which I am very fond of. Our nice lambda expressions are a lot better as a syntax for writing anonymous methods than what anonymous delegates ever were. The sometimes well-known secret here, however, is that the same lambda expression code could mean two completely different things, depending on the context. Given the following code:

DoStuff<string>(stringValue => Console.WriteLine(stringValue));

We would pass completely different things to our DoStuff-method depending on how that method is defined (Which could be compared to sending a constant integer 1 as a parameter to method. If the method takes an integer, the parameter would be compiled as an integer but if the parameter is defined as a double, the compiler would help us and change the 1 to a double with the value 1.0d). If the parameter is defined as an Action<string>, then we would receive a precompiled Action which we could use. If, on the other hand, the parameter is defined as Expression<Action<string>> then we would instead get an expression tree. Using this expression tree, we could compile and execute it if we want to, but we also have the possibility to examine the expression tree (which is very useful, for example when creating an IQueryable or IQbservable).

The GetMemberName-method

What I would want in the above examples is that if I would rename the property or parameter using the refactoring tools in Visual Studio, the string would automatically be updated as well. And if I, for some reason, would have misspelled or forgot to update the string, I would like a compiler error. The GetMemberName-method will help us achieve this goal.

public static class ObjectExtensions
{
    public static string GetMemberName<T, K>(this T obj, Expression<Func<T, K>> expression)
    {
        if (expression == null)
            obj.GetMemberName(_ => expression);
        MemberExpression memberExpression = expression.Body as MemberExpression;
        if (memberExpression == null)
            throw new ArgumentException("Expression of type " 
                + expression.Body.Type.ToString() 
                + " is not supported by the GetMemberName method."
                + " Only MemberExpressions are currently supported.", obj.GetMemberName(_ => expression));
        return memberExpression.Member.Name;
    }
}

We could then change our code above to something similar to the following:

public class MyClass:INotifyPropertyChanged
{
    public MyClass(IRepository repository)    
    {
        if (repository == null)
            throw new ArgumentNullException(this.GetMemberName(_ => repository));
    }

    private string _name;
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value;
            OnNotifyPropertyChanged(this.GetMemberName(_ => Name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName);
    }
}

Tiny drawbacks

Of course, for some unfortunate reason, there are no silver bullets which solve every problem, even though this one is at least silver coated. The drawback of using the GetMemberName instead of using a constant string is performance. I have performed very naive performance tests on the GetMemberName-method and it has shown that the method call took up to 30 milliseconds to perform on my laptop (which isn’t a very powerful laptop). In almost all cases I believe these milliseconds are worth getting rid of the strings, but if I would set the property 100 times per second this could be a problem (on the other hand, if I update it that frequently, perhaps it isn't a good fit for INotifyPropertyChanged). Therefore, I try to use this approach as often as I can, instead of using unnecessary magic string, and only if it would become a problem, I would consider writing the name as a string.

Unit Testing

It could be added, of course, that if you have unit tests which cover the PropertyChanged events when setting parameters this could be a non-issue, as long as you start a property rename with renaming in the tests and there renaming the string. Perhaps the GetMemberName method could be good to use in the unit test and to not use in the application code?

Custom scroll buttons for the ScrollViewer control in Silverlight

Earlier today I had a discussion with a co-worker who needed to replace the default template of the ScrollViewer control, in order to replace the ScrollBar with custom buttons. He had found some example of doing this in WPF, but the same sample did not work in Silverlight (the samples relied on routed command which aren’t available in Silverlight) so I decided to write up a sample of my own.

Disclaimer: The sample is very rudimentary and may not be the best way to achieve this (also the placement of the commands might be questionable). Use the sample at your own risk.

To begin with, we need a ScrollViewer with some content.

<Grid x:Name="LayoutRoot" Background="White" Height="100" Width="120">
    <ScrollViewer>
        <StackPanel>
            <TextBlock Text="Text1"/>
            <TextBlock Text="Text2"/>
            <TextBlock Text="Text3"/>
            <TextBlock Text="Text4"/>
            <TextBlock Text="Text5"/>
            <TextBlock Text="Text6"/>
            <TextBlock Text="Text7"/>
            <TextBlock Text="Text8"/>
            <TextBlock Text="Text9"/>
        </StackPanel>
    </ScrollViewer>
</Grid>

Additionally, we will be using a stripped down version of the RelayCommand. I use a stripped down version since I really don’t need any more functionality for this sample.

public class RelayCommand<T>:ICommand
{
    private Action<T> _action;

    public RelayCommand(Action<T> action)
    {
        this._action = action;
    }

    public bool CanExecute(object parameter)
    {
        return true;
    }

    public event EventHandler CanExecuteChanged;

    public void Execute(object parameter)
    {
        if (!(parameter is T))
            throw new ArgumentException("The parameter must be of type T", "parameter");
        _action((T)parameter);
    }
}

The default look of the ScrollViewer control, using the above Xaml looks similar to this:

The default look of the ScrollViewer control, using the Content we supplied

And our goal is to make it look like this:

The modified look of the ScrollViewer control, using buttons instead of the ScrollBar, which we have as our aim

Quite an improvement, right?

I admit that it might not be prettiest design for my custom scroll buttons. To my defence I will say that beauty is not the aim of this post and… well, at least it works.

To get the ScrollViewer to look like what we want, we start by changing the declaration of the ScrollViewer to start using a custom template (if you do this in production code, you might want to define it as a style and set the Template property to be your ContentTemplate, especially since you will probably want to set other properties as well, but in order to keep the code a little shorter here, we’ll just set the template directly) which we will define later. The new declaration of the ScrollViewer should be:

<ScrollViewer Template="{StaticResource MyScrollViewer}">
...

The next step is to create the actual Template that we have just referenced. In our template, we’ll create two RepeatButtons (using RepeatButtons instead of Buttons allows the user to keep the button pressed to keep scrolling until released), to serve as up and down buttons, and between them we’ll place the ScrollContentPresenter (which will display the content of the ScrollViewer control, i.e. the TextBlocks).

<ControlTemplate x:Key="MyScrollViewer" TargetType="ScrollViewer">
    <StackPanel Width="100">
        <RepeatButton Content="Up" Command="{Binding ScrollUpCommand, ElementName=_this}"
		CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
        <ScrollContentPresenter Height="50" x:Name="ScrollContentPresenter"/>
        <RepeatButton Content="Down" Command="{Binding ScrollDownCommand, ElementName=_this}"
		CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
    </StackPanel>
</ControlTemplate>

So, what is the ScrollUpCommand used in the code above? The ScrollUpCommand, as well as the ScrollDownCommand, is defined in the code behind of the control, using the following code:

public ICommand ScrollUpCommand
{
	get
	{
		return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineUp());
	}
}

public ICommand ScrollDownCommand
{
	get
	{
		return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineDown());
	}
}

And there we have it, our nice little ScrollViewer without the default ScrollBar. The secret sauce lies in the CommandParameter, sending the ScrollContentPresenter which we want to scroll as a parameter to the command when it executes. Have fun with the code! Here is the full code for the sample:

MainPage.xaml:

<UserControl x:Class="SilverlightApplication11.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" x:Name="_this">
    <UserControl.Resources>
        <ControlTemplate x:Key="MyScrollViewer" TargetType="ScrollViewer">
            <StackPanel Width="100">
                <RepeatButton Content="Up" Command="{Binding ScrollUpCommand, ElementName=_this}" 
			CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
                <ScrollContentPresenter Height="50" x:Name="ScrollContentPresenter"/>
                <RepeatButton Content="Down" Command="{Binding ScrollDownCommand, ElementName=_this}" 
			CommandParameter="{Binding ElementName=ScrollContentPresenter}"/>
            </StackPanel>
        </ControlTemplate>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White" Height="100" Width="120">
        <ScrollViewer Template="{StaticResource MyScrollViewer}">
            <StackPanel>
                <TextBlock Text="Text1"/>
                <TextBlock Text="Text2"/>
                <TextBlock Text="Text3"/>
                <TextBlock Text="Text4"/>
                <TextBlock Text="Text5"/>
                <TextBlock Text="Text6"/>
                <TextBlock Text="Text7"/>
                <TextBlock Text="Text8"/>
                <TextBlock Text="Text9"/>
            </StackPanel>
        </ScrollViewer>
    </Grid>
</UserControl>

MainPage.xaml.cs:

using System.Windows.Controls;
using System.Windows.Input;

namespace SilverlightApplication11
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        public ICommand ScrollUpCommand
        {
            get
            {
                return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineUp());
            }
        }

        public ICommand ScrollDownCommand
        {
            get
            {
                return new RelayCommand<ScrollContentPresenter>(scroll => scroll.LineDown());
            }
        }
    }
}

RelayCommand.cs:

using System;
using System.Windows.Input;

namespace SilverlightApplication11
{
    public class RelayCommand<T>:ICommand
    {
        private Action<T> _action;

        public RelayCommand(Action<T> action)
        {
            this._action = action;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged;

        public void Execute(object parameter)
        {
            if (!(parameter is T))
                throw new ArgumentException("The parameter must be of type T", "parameter");
            _action((T)parameter);
        }
    }
}