Bookmark and Share

Remove Generic Parameter Refactoring

by KodefuGuru 6. August 2010 12:30

I needed to remove an extraneous generic parameter from two classes in a 2008 project. One of the classes was BusinessObjectList<TList, TItem>, and TList wasn’t used and it ended up junking up the code throughout the solution. I was tired of looking at it and its bizarre subclasses like EmployeeList : BusinessObjectList<EmployeeList, Employee>.

I will note how it could be useful: if any of the methods on BusinessObjectList were returning the subclassed list as part of a fluent interface. But nothing like this exists. I’m not even a fan of defined list classes. Why should you limit yourself when there are other sequence possibilities? What if I had an array of the particular BusinessObject?  I think extension methods on IEnumerable<BusinessObject> are better and it plays better with LINQ (I don’t have to redefine every LINQ method to make it return the list). These are fluent by their nature anyway since you typically make the method yield out the objects creating an IEnumerable<T>.

But, the hard lists are there, and I believe the cost of removing them is too high at this point in time but it’s something I’ll have my eye on if the opportunity exists. Keeping the code tight by removing the extraneous generic is worth it though considering some other framework issues I will be tackling. The problem is that hundreds of classes inherited from this class and the other, and a manual edit would take forever. This refactoring should be quick.

I checked all of my tools, but none had a “remove generic parameter” refactoring. Would I have to do this by hand? Of course not, I’m a programmer. What tool do we have for matching stuff like a BusinessObjectList<X, Y>? How about RegEx?

I pop up the Find/Replace dialog, and immediately type a regex that should match everything I want to replace. It doesn’t work. Now, I’m not an expert in that sort of thing, but surely I can write something that simple? After a few minutes of trying it out, I start searching and discover Jeff Atwood has already talked about this oddity in Visual Studio.

After learning Visual Studio’s flavor of regex, I finally achieved a somewhat bizarre construct for removing a generic parameter. Find what: BusinessObjectList\<:i,:b{:i}\> and Replace with: BusinessObjectList\<\1\>.

clip_image002

The class everything was inheriting from was BusinessObjectList, so I wrote that in and escaped the < and >. :i marks a C/C++ identifier (which works great with C#!) and :b matches tab or space. I enclosed the second :i with curly braces so I could use it as an identifier in the replace regex with \1.

There may not have been a fancy tool to achieve this, but the results were the same and it didn’t take much time. It certainly beats replacing the code by hand.

Bookmark and Share

Why You Should Use the Null Coalescing Operator

by KodefuGuru 20. December 2009 02:49

Introduced in C# 2.0, the null coalescing operator (??) allows one to program in a concise, declarative fashion when performing null checks. This was important in 2005 as it made it easier to utilize another important feature: nullable types.

Nullable types solved the problem of representing a value type that also contained a null value. This representation of value types is common in databases, and oftentimes caused problems when doing relational to object mapping.

Nullable types are generic structs that can be declared as Nullable<T>. However, they are often used with the value type and a question mark, e.g. int?. Here’s an example of how to use a nullable type and the null coalescing operator.

int number = nullable ?? default(int);

The null coalescing operator isn’t necessary, however. As I mentioned above, it makes your code more concise, and declarative. There are two other ways to do this.

The imperative way:

int number = default(int);

if (nullable.HasValue)
{
    number = nullable.Value;
}

The longer, declarative way:

int number = nullable.HasValue ? nullable.Value : default(int);

The latter example is too long. The null coalescing operator achieves the same result with much less code, so it is preferable.

The imperative example will elicit some calls for support. I’ve heard the argument from several people before: “developers don’t understand this ?? thing, everyone understands if statements.” If that’s true in your organization, I would recommend teaching it to them. Start using the operator so they get used to it. If you keep providing them imperative crutches, they will continue to use them. No one learned standard object oriented programming overnight either. To continue pushing imperative code over reasonable declarative alternatives is akin to writing 150 line methods because that’s the way you did it in C.

So why am I writing about the null coalescing operator now, so many years after it came into being? The answer is that it can be combined with newer language features to make your code even more powerful.

The null coalescing operator with object initializers

In this example, I broke out some old school ADO.NET. The AdventureWorks database has a WorkOrder table with an EndDate column that allows nulls.

public static WorkOrder GetWorkOrderById(int id)
{
    using (var connection = 
        new SqlConnection
            (ConfigurationManager.ConnectionStrings["AdventureWorks"].ConnectionString))
    {
        connection.Open();
        var command = new SqlCommand(Queries.GetWorkOrderById, connection);
        command.Parameters.Add(new SqlParameter("@WorkOrderId", id));
        var reader = command.ExecuteReader();

        if (!reader.HasRows)
        {
            throw new ApplicationException(Exceptions.WorkOrderNotFound);
        }

        reader.Read();
        return new WorkOrder
        {
            Id = reader.GetInt32(0),
            Quantity = reader.GetInt32(1),
            Stock = reader.GetInt32(2),
            Scrapped = reader.GetInt16(3),
            StartDate = reader.GetDateTime(4),
            EndDate = reader[5] as DateTime? ?? DateTime.MaxValue,
            DueDate = reader.GetDateTime(6),
            ModifiedDate = reader.GetDateTime(7)
        };
    }
}

Unless the underlying schema changes, we will have a value for most of the columns. EndDate allows nulls in the database, but the WorkOrder object is straight DateTime in my sample application. The WorkOrder object has its values set in an object intializer, which requires a declarative syntax for all property initializations. The solve this in the simplest way possible, I used the null coalescing operator to make the end date the maximum possible value if the database has a null value.

The null coalescing operator with LINQ statements

LINQ is declarative by design, which makes it a good partner with the null coalescing operator where appropriate. Although you may never use it with a predicate (unless it’s a bool?), it is possible to use it with a selector.

int?[] dirtyNumbers = new int?[] { 1, null, 2, null, 3, 4, null, 5 };
var numbers = dirtyNumbers.Select(n => n ?? default(int));

You can extend this further make null have a meaning, such this function where null becomes the adjacent number in the aggregate function.

var values = new double?[] { 1.01, null, 1.24, 1.53, null, 1.93, 1.12 };
var value = values.Aggregate((x, y) => (x ?? y) * (y ?? x));

A more common scenario is that you want to retrieve an element out of enumerable. This is typically the first element, or perhaps it’s a single element. In any case, if it’s not found, you must retrieve it from elsewhere.

var workOrder = workOrders.SingleOrDefault(w => w.Id == id) ?? GetWorkOrderById(id);

I still see so many pieces of code where someone uses FirstOrDefault, or SingleOrDefault but leaves off the null coalescing operator. Instead, the programmer turns to imperative logic to handle the variable being null. It is important to point out that the null coalescing operator is useful for more than nullable types; it is useful for all reference types.

Bookmark and Share

Inane Generic Usage

by KodefuGuru 29. September 2009 19:04

in·ane (ĭn-ān') adj. in·an·er, in·an·est
One that lacks sense or substance.

The American Heritage® Dictionary of the English Language, Fourth Edition
Copyright © 2009 by Houghton Mifflin Company.
Published by Houghton Mifflin Company. All rights reserved.

One of the first signs that code needs to be refactored is that it looks complex. Complex solutions are rather easy to come by, but are far less maintainable than their harder to write, easier to read brethren. Like any well-crafted sculpture, it didn’t like start that way, and it requires work to craft that beautiful piece of code. But sometimes you come across code for which there is no reason for the complexity. It appears that someone just wanted to type extra characters throughout their code.

A while back, I analyzed another developer’s code that used a lot of generics. Since nothing was being returned from many of these methods, I decided to look at the signature to discover why the generics were necessary. Here’s one of them.

public static void PrintReport<T>(T report)
{
    WriteEvent(report.ToString());
    IReport r = report as ClientReport;
    if (r != null)
    {
        //Do stuff
    }
    r = report as EmployeeReport;
    if (r != null)
    {
        //Do stuff
    }
}

Looking at this, you may notice there is absolutely no reason for the generic declaration. There are no constraints on it, so it is the same thing as declaring the parameter as an object. Everwhere this was used, it was calling PrintReport<ClientReport>(report) and so on. I pointed this out to the developer, and said it should be refactored because a) the generic adds no value, and b) there are object oriented solutions that are much better than static methods and casting. Of course, this is what I got back.

public static void PrintReport<T>(T report) where T : IReport
{
    WriteEvent(report.ToString());
    IReport r = report as ClientReport;
    if (r != null)
    {
        //Do stuff
    }
    r = report as EmployeeReport;
    if (r != null)
    {
        //Do stuff
    }
}

There’s now a constraint! A constraint that has no meaning other than preventing someone from printing an object that isn’t an IReport. Of course, the same thing could be accomplished by making the parameter be an IReport rather than a T. I then showed the developer how the generic adds absolutely no value (I think I saw a grimace as I cut all of those <xReport>s out of the myriad of classes making that call). I then explained how when I see things like casting in a method like that, it makes me consider that perhaps that behavior belongs on the class, perhaps called by a method defined on the interface.

public static void PrintReport(IReport report)
{
    WriteEvent(report.ToString());
    report.DoStuff();
}

For future reference, inane usage of generics involves using a generic on a method, not involving a parameterized class, where 1) the return type isn’t the generic type, and 2) the constraint isn’t new() or class.

If someone can think of a situation where this is actually useful, post a comment.

Also, another quick lesson. The developer did place PrintReport<ClientReport> in many places, but did you know that this wasn’t even necessary? With generic methods, you get generic inference. The compiler will determine the type for you. This  is very handy with LINQ. Without generic inference, you would have to write ugly methods like strings.Where<string>(s => s.StartsWith(“s”)).

Bookmark and Share

Generics Don't Make Me Sad

by KodefuGuru 15. September 2008 18:15

I came across an interesting blog post today entitled, "C# generics make me sad..." by Matt Sheppard.

Matt has an issue with generic Lists, in that you can't easily convert from one to another even if one constraint is inherited from the other constraint.

List<String> sl = new List<String>();
List<Object> ol = new List<Object>();
ol = sl;

This will throw the error "Cannot implicitly convert type ‘System.Collections.Generic.List<string>’ to ‘System.Collections.Generic.List<object>’ ."

Matt then tries to cast sl to List<Object>. This fails too, as List<String> and List<Object> are two different classes. String may inherit from Object, but List<String> does not inherit from List<Object>.

One responder provided a link that goes into detail of why this doesn't work. However, the point of this post is to provide a simple solution to Matt's main gripe that "it would be nice to have a clean way to perform an explicit conversion rather than having to manually loop through..."

List<T> does have a method called ConvertAll, although you have to pass in a delegate. It makes for messy looking code, but it is the correct way to solve this problem.

ol = sl.ConvertAll<Object>(new Converter<String, Object>(delegate(String s)
{
      return s;
}));

There is another way to do this with other methods on List<T>. The methods aren't necessarily meant to convert one list to another but result in less mess.

ol.AddRange(sl.ToArray());

I would let either block pass a code review barring other cirumstances.

KodefuGuru.GetInfo()

Chris Eargle
LinkedIn Twitter Technorati Facebook

Chris Eargle
C# MVP, INETA Community Champion


MVP - Visual C#

 

INETA Community Champions
Friend of RedGate
Telerik .NET Ninja
Community blogs & blog posts

I am a #52er

I have joined Anti-IF Campaign


World Map

Tag cloud

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010