views:

155

answers:

3

I've got a method which currently takes an IList as a parameter, where UserBO is similar to the following:

public class UserBO {
    public string Username { get; set; }
    public string Password { get; set; }
    public string Pin { get; set; }
}

public class SomeClass {
    // An example method giving the basic idea of what I need to do
    public void WriteUsers(IList<UserBO> users) {
        // Do stuff with users
        for (var user in users) {
            Console.WriteLine(String.Format(User: {0}: {1}, users.Username, Hash(users.Pin)); // Now needs to optionally be users.Password
        }
    }

    private string Hash(string pin) {
        return // Hashed Pin
    }
}

This method then uses the Username/Pin pairs to create some XML used by another program (we'll use the above method as an example).

The thing is, now I need to be able to produce the same code except using the Password field instead of the Pin field (there's a good reason for having both fields).

Instead of just creating another method with a similar name, I'd prefer to refactor the code so as to remove the BO specific code from this class entirely, and make it so that the decision about what class/members to use are made not in the method itself but the code calling it.

One option would be to pass an IDictionary and use the Linq ToDictionary method to create a dictionary on the fly in the calling code. This would however lose the ordering of the items (which would be nice but not essential to keep). I could use an IList or something, but that would be more difficult to convert the IList into.

Does anybody have any good suggestions of how to do this?

P.S. If anybody has a better idea of how to title this post, feel free to have a go at it.

+2  A: 

It's not clear exactly what you need to do with the strings after formatting. You could make the method take an IEnumerable<string>, and then make the calling code:

WriteUsers(users.Select(user => string.Format("{0}: {1}", 
                                              users.Username, users.Pin)));

Whether that works for you or not will depend on the details.

Jon Skeet
In my case I do need to use the usernames/Pins in different places and in different formats, so I don't think that would work. I'll edit the post to make that more clear. Thanks though!
Lawrence Johnston
+2  A: 

You could also use Expressions:

 WriteUsers(IList<T> users, u => u.Username, u => u.Password);

if you're using Net 3.5.

gcores
I think that might work. I'm going to go test it. Thanks!
Lawrence Johnston
+1  A: 

First off, for usability, I recommend switching your IList to an IEnumerable. Provided you're not doing any other logic that requires the list, it opens up your class to being usable by more users, and has no downside.

If you want to completely eliminate the selection of what is being printed from your class, I can think of a couple of options.

One (although potentially less usable) would be to use reflection. If perf. isn't a huge issue, you could refactor it to have something like:

WriteElements(IEnumerable elements, params string[] propertiesToWrite)

Then you could just refactor the method so that it uses reflection to get the properties from the type specifier for T, and write out any number of them. The caller would then do:

WriteElements(listOfUsers, "Username", "Password");

A second, probably cleaner, option would be to refactor it to take:

WriteElements(IEnumerable<UserBO>, Func<UserBO,string>);

You could then call it with :

// Call using password
WriteElements(listOfUsers, user => user.Password);

// or call using pin
WriteElements(listOfUsers, user => user.Pin);
Reed Copsey