3

Possible Duplicate:
C# - Is there a better alternative than this to ‘switch on type’?

My company legacy code has something as follow

public override Uri GetUri(object obj)
{
    if ((obj is Entry) || (obj is EntryComment))
    {
        //
    }
    if (obj is Blog)
    {
        //
    }

    // if obj is blah blah blah
}

This method is just ugly. I want to refactor it, but I don't know a technique to iterate over "possible" types that obj can be.

How can I refactor this?

Thank you.

Community
  • 1
  • 1
Delta76
  • 13,931
  • 30
  • 95
  • 128
  • I added the region directive to demonstrate how ugly the code is :-s – Delta76 May 10 '11 at 08:36
  • 2
    Could you move the code inside the if-statement blocks into the types themselves? That way your method would just be: `return obj.Uri;`. – Lasse V. Karlsen May 10 '11 at 08:36
  • @Lasse V. Karlsen, +1 for your comment. – Sandeep G B May 10 '11 at 08:41
  • see also http://stackoverflow.com/questions/156467/switch-pattern-matching-idea http://stackoverflow.com/questions/7252186/switch-case-on-type-c-sharp http://stackoverflow.com/questions/7542793/how-to-use-switch-case-on-a-type http://stackoverflow.com/questions/4478464/c-sharp-switch-on-type http://stackoverflow.com/questions/298976/c-sharp-is-there-a-better-alternative-than-this-to-switch-on-type – Mikhail Poda May 01 '12 at 11:56
  • and http://stackoverflow.com/questions/94305/what-is-quicker-switch-on-string-or-elseif-on-type http://stackoverflow.com/questions/6304815/why-is-this-switch-on-type-case-considered-confusing http://stackoverflow.com/questions/10115028/best-way-to-switch-behavior-based-on-type http://stackoverflow.com/questions/2551773/c-sharp-which-is-the-best-alternative-to-switch-on-type – Mikhail Poda May 01 '12 at 11:56

5 Answers5

5

A couple of options:

  • If you're using C# 4, you could use dynamic typing, and split the method into a number of overloads:

    public Uri GetUri(dynamic obj)
    {
        return GetUriImpl(obj);
    }
    
    private Uri GetUriImpl(Entry entry)
    {
        ...
    }
    
    private Uri GetUriImpl(EntryComment comment)
    {
        ...
    }
    

    In this case you'd probably want some sort of "backstop" method in case it's not a known type.

  • You could create a Dictionary<Type, Func<object, Uri>>:

    private static Dictionary<Type, Func<object, Uri>> UriProviders = 
        new Dictionary<Type, Func<object, Uri>> {   
        { typeof(Entry), value => ... },
        { typeof(EntryComment), value => ... },
        { typeof(Blog), value => ... },
    };
    

    and then:

    public Uri GetUri(object obj)
    {
        Func<object, Uri> provider;
        if (!UriProviders.TryGetValue(obj.GetType(), out provider))
        {
            // Handle unknown type case
        }
        return provider(obj);
    }
    

    Note that this won't cover the case where you receive a subtype of Entry etc.

Neither of these are particularly nice, mind you... I suspect a higher level redesign may be preferable.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
4

You can also refactor this with interfaces

public interface IHasUri
{
   public Uri GetUri();
}

and implement this interface in all you hierarchy. Than you can use

public Uri GetUri(object obj)
{
    IHasUri hasUri = obj as IHasUri;
    if(hasUri != null)
      Uri uri = hasUri.GetUri();

    // bla bla bla 
}
Stecya
  • 22,896
  • 10
  • 72
  • 102
1

I think Lasse V. Karlsen has the right of it in his comments, a redesign is more appropriate perhaps

You could create an interface like Stecya suggests

public interface IUriAccessible { //or some sort of a more descriptive name
    Uri Url {get;}
}

and then for each object that you care for, eg Entry, you could

public class Entry:IUriAccessible {
    //... other code here
    public Uri Url {
        get {
            //return uri here
        }
    }
}

and now you can just call it on the object

var entry = new Entry();
var uri = entry.Url;
bottlenecked
  • 2,079
  • 2
  • 21
  • 32
0

You can have a List<Type>() with all types you want to check for and iterate that list. but I don't think that makes the code faster.

DanielB
  • 19,910
  • 2
  • 44
  • 50
  • I don't want "Faster" code, but "more readable" code :). The problem is, the processing code for each type is not the same, so I don't think List is suitable. Switch is more suitable choice – Delta76 May 10 '11 at 08:37
0

You can't switch-case types.

A switch expression or case label must be a bool, char, string, integral, enum, or corresponding nullable type

abatishchev
  • 98,240
  • 88
  • 296
  • 433