views:

177

answers:

10

Consider the following (nasty) code:

    /// <summary>
    /// Calls matching process error code on response.Code
    /// </summary>
    /// <param name="response">Actually will be of type Response or extend it</param>
    /// <returns>true for successful response, false otherwise</returns>
    private static bool ProcessErrorCode(object response)
    {
        bool isOkay = false;
        const string unknown = "UNKNOWN";
        string errCode = unknown;
        if (response.GetType() == typeof(Response<AResponseCode>))
        {
            AResponseCode code = ((Response<AResponseCode>)response).Code;
            isOkay = code == AResponseCode.Ok;
            errCode = code.ToString();
        }
        if (response.GetType() == typeof(Response<BResponseCode>))
        {
            BResponseCode code = ((Response<BResponseCode>)response).Code;
            isOkay = code == BResponseCode.Ok;
            errCode = code.ToString();
        }
        if (response.GetType() == typeof(DataResponse<CResponseCode,string>))
        {
            CResponseCode code = ((DataResponse<CResponseCode, string>)response).Code;
            isOkay = code == CResponseCode.Ok;
            errCode = code.ToString();
        }
        if (isOkay)
        {
            return true;
        }
        string msg = "Operation resulted in error code:" + errCode;
        LogErrorCode(msg);
        return false;
    }

I am trying to figure out a way to reduce castings and imrove the method style. I have no code ownership on Response<TResponseCode>, DataResponse<TResponseCode,string>, AResponseCode, BResponseCode, CResponseCode

response parameter will be of type Response<TResponseCode> or inherit from it (DataResponse<TResponseCode,string> : Response<TResponseCode>)

All *ResponseCode are Enums and they all have an *ResponseCode.Ok entry

A: 

I'd swap a switch statement for all the ifs.

5arx
I'd be interested to see how you would make that code simpler with a switch statement - how about an example :)
Andras Zoltan
It wouldn't - `Type` is not an integral type, there's nothing to switch on here.
annakata
What about switch(typeOf(blah)) ?
5arx
+1  A: 

Ideally, you'd give Response<TResponseCode> a common interface with an 'OK' function on it. Seeing as you can't, your solution is going to look a bit hacky.

Given that constraint, I'd extract a couple of methods - static bool IsResponseOk(object response) and static string GetResponseError(object response) - which would result in easier to read code, but still not brilliant.

Joe Gauterin
A: 

This replaces my old answer as it clearly bombed :) (them's the breaks)

I don't expect this'll do any better - but you might find the approach interesting.

The basic idea is to define a result type that contains your IsOkay and ErrCode values, and then define a dictionary of delegates (keyed by the type of the object that they handle) that you consult. To add new handlers you simply add another delegate to the dictionary.

public class ResponseResult{
  public bool IsOkay;
  public string ErrCode;
}

public static class ResponseExtracter
{
  //STARTING OFF HERE WITH THE NEW VERSION OF YOUR METHOD
  public static bool ProcessErrorCode(object response)
  {
    Func<object, ResponseResult> processor = null;
    ResponseResult result = new ResponseResult() 
    { 
      IsOkay = false, ErrCode = "UNKNOWN"
    };

    //try to get processor based on object's type
    //then invoke it if we find one.
    if (_processors.TryGetValue(response.GetType(), out processor))
      result = processor(response);

    if (result.IsOkay)
      return true;
    string msg = "Operation resulted in error code:" + result.ErrCode;
    LogErrorCode(msg);
    return false;
  }
  //A lot better no?

  //NOW FOR THE INFRASTRUCTURE
  static Dictionary<Type, Func<object, ResponseResult>> _processors 
    = new Dictionary<Type, Func<object, ResponseResult>>();

  static ResponseExtracter()
  {
    //this can be replaced with self-reflection over methods
    //with attributes that reference the supported type for
    //each method.
    _processors.Add(typeof(Response<AResponseCode>), (o) =>
    {
      AResponseCode code = ((Response<AResponseCode>)o).Code;
      return new ResponseResult
      {
        IsOkay = code == AResponseCode.Ok,
        ErrCode = code.ToString()
      };
    });

    _processors.Add(typeof(Response<BResponseCode>), (o) =>
    {
      BResponseCode code = ((Response<BResponseCode>)o).Code;
      return new ResponseResult
      {
        IsOkay = code == BResponseCode.Ok,
        ErrCode = code.ToString()
      };
    });

    _processors.Add(typeof(DataResponse<CResponseCode, string>),
      (o) =>
      {
        CResponseCode code = ((DataResponse<CResponseCode, string>)o).Code;
        return new ResponseResult
        {
          IsOkay = code == CResponseCode.Ok,
          ErrCode = code.ToString()
        };
      });
  }
}

Performance-wise it's better than it looks because the Dictionary<Type, TValue> is actually hashing on the integer value that underpins the type's TypeHandle. This is in fact an Int64 - so only the first 32 bits are used, but in practise it's highly unlikely that two types share the same first 32 bits of their handle.

Andras Zoltan
Why on earth would you not just use `is` in your tests?
annakata
because `is` plus a cast is actually two cast operations. `as` does a type-check and cast in one operation thus making it faster at runtime plus also easier to read. imho
Andras Zoltan
@annakata: so I guess my counter question to you is "why on earth would you perform two identical casts one after another?"
Andras Zoltan
Because you're making an assignment as a side-effect which is a terribly dangerous thing to do on the grounds of readability and complexity, expecially when the reasoning is performance for a highly performant set of operations anyway. Every line should do exactly one thing.
annakata
And really it's false economy here anyway - look at all those declarations and if tests you're doing!
annakata
That doesn't really answer my question as to why you would do two casts in a row; you've just tried to point out more weaknesses in my suggestion. Anyway. The if test is a !=null - practically the fastest comparison there is; plus just one cast makes this code faster then the OPs and the `is` approach for that matter. You might well disagree with the assign-and-test approach, but it does exactly what the OP wants - reduces the casting. Whether or not it's more readable is more down to taste, for me it tastes great :). But one person's meat is another person's poison and all that...
Andras Zoltan
Er, I think I did - you're doing messy things where you need to be clear and you're doing this for the sake of performance where the other course of action is really very efficient anyway. And then you're sacrificing "all" of your performance gains with the additional declarations and assignments and if tests. This really isn't a matter of taste it's a matter of your ability to adapt and maintain code. Not trying to offend, but this is not a good pattern to be replicating.
annakata
Jeez, if your big problem here is about the test-and assign, that can very easily be moved to two separate lines! But, hey, I've got rid of that solution and put up another one. It's completely different but I'm sure will generate even more controversy
Andras Zoltan
A: 

From a performance perspective, I'd replace .GetType() == typeof() with the is operator, eg:

if( response is DataResponse<CResponseCode,string> )

The following benchmark shows a performance improvement of roughly 3x on my machine:

var f = new List<string>();
var dummy = 0;

Stopwatch sw = new Stopwatch();

sw.Start();
for(int i=0; i< REPS; i++)
    if(f.GetType() == typeof( List<string> )) dummy++;
sw.Stop();
Console.WriteLine(sw.Elapsed);

sw.Reset();

sw.Start();
for(int i=0; i< REPS; i++)
    if(f is List<string> )  dummy++;
sw.Stop();

Console.WriteLine(sw.Elapsed);

// Outputs
00:00:00.0750046
00:00:00.0261598
Winston Smith
+1  A: 

You could use a generic subroutine for this:

    // Mocking your classes, just to check if it compiles. You don't need this.
    class Response<T> { 
        public T Code { get { return default(T); } } 
    }
    enum AResponseCode { Ok }
    enum BResponseCode { Ok }
    enum CResponseCode { Ok }
    static void LogErrorCode(string msg) { }

    private static bool ProcessErrorCode(object response)
    {
        bool isOkay;
        string errCode;

        if (!TryProcessErrorCode(response, AResponseCode.Ok, out isOkay, out errCode))
            if (!TryProcessErrorCode(response, BResponseCode.Ok, out isOkay, out errCode))
                TryProcessErrorCode(response, CResponseCode.Ok, out isOkay, out errCode);

        if (isOkay)
        {
            return true;
        }
        string msg = "Operation resulted in error code:" + errCode;
        LogErrorCode(msg);
        return false;
    }

    // TResponseCode is automatically inferred by passing the okCode
    private static bool TryProcessErrorCode<TResponseCode>(
        object response, TResponseCode okCode, 
        out bool isOkay, out string errCode)
    {
        var resp = response as Response<TResponseCode>;
        if (resp == null)
        {
            isOkay = false;
            errCode = "UNKNOWN";
            return false;
        }
        else
        {
            isOkay = okCode.Equals(resp.Code);
            errCode = resp.Code.ToString();
            return true;
        }
    }
Heinzi
You've assumed that the first type check that succeeds is sufficient for the results but the original code doesn't make this assumption. If Response<T> is a class then this is reasonable since no more than one of the type checks could possibly succeed; however, despite breaking the naming convention, Response<T> and DataResponse<T, U> might be interfaces which means more than one the type checks could succeed and if that's true, your code would behave differently to the original (first vs. last successful check).
Daniel Renshaw
@Daniel: Good point! If that is the case, the order of the `if` s should be reversed to reflect the order of precedence present in the original code (`Response<BResponseCode>.Code` overwrites the result of `Response<AResponseCode>.Code`). There's one more point, by the way, in which my (and your) code differs from the original behavior: A `Response<CResponseCode>` is always considered a valid response, even if it is not a `DataResponse<CResponseCode, string>`.
Heinzi
@Heinzi: yep, you're right. I had a version that wouldn't have changed that behaviour (by doing an explicit cast for each outside the "test" function but I'll leave it as it is for now.
Daniel Renshaw
A: 

Refactored thus, and I'd have been faster if IE hadn't freaked out and reloaded the page spontaneously. :(

I agree with others that this ideally should be gutted and mocked/encapsulated/extended to get where you want, but working within the method as a point of least impact and as an instructional:

  bool isOkay = false; 
  string errCode; // you don't need to default this to anything because it won't be empty if you need to use it

  if (response is Response<AResponseCode>) // "is" is a faster and more expressive test
  { 
    var code = (response as Response<AResponseCode>).Code; // "as" is a faster conversion
    isOkay = (code == AResponseCode.Ok); // Readability is awesome!
    errCode = code.ToString(); // This still sucks
  } 
  else if (response is Response<BResponseCode>) // elsif logically exclusive tests
  { 
    var code = (response as Response<BResponseCode>).Code; 
    isOkay = code == BResponseCode.Ok; 
    errCode = code.ToString(); 
  } 
  else if (response is DataResponse<CResponseCode,string>) 
  { 
    var code = (response as DataResponse<CResponseCode, string>).Code; 
    isOkay = (code == CResponseCode.Ok); 
    errCode = code.ToString(); 
  } 

  // Test what you mean to express, i.e. if this isn't ok I need to log it
  if (!isOkay) 
  { 
    // you don't need a temp variable here...
    // and why aren't you just throwing an exception here? Is not being ok a regular unexceptional event, but one you still need to log? Really?
    LogErrorCode("Operation resulted in error code:" + errCode);
  } 

  // And try not to return bool literals, it's again unexpressive
  return isOkay;
annakata
I'd use `as` straight off - `is` is simply shorthand for `((o as T) != null)`
Andras Zoltan
It's really not - check the IL, you'll be surprised. My point though has always been that expressign what you mean is what matters most.
annakata
+1  A: 

You can get a slightly cleaner solution using generics:

private static void TestErrorCode<TCode>(object response, TCode ok, ref bool isOkay, ref string errCode)
{
    Response<TCode> responseTyped = response as Response<TCode>;

    if (responseTyped == null)
    {
        return;
    }

    TCode code = responseTyped.Code;
    isOkay = code.Equals(ok);
    errCode = code.ToString();
    return;
}

private static bool ProcessErrorCode(object response)
{
    bool isOkay = false;
    string errCode = "UNKNOWN";

    TestErrorCode(response, AResponseCode.Ok, ref isOkay, ref errCode);
    TestErrorCode(response, BResponseCode.Ok, ref isOkay, ref errCode);
    TestErrorCode(response, CResponseCode.Ok, ref isOkay, ref errCode);

    if (isOkay)
    {
        return true;
    }

    LogErrorCode("Operation resulted in error code:" + errCode);
    return false;
} 
Daniel Renshaw
That's not equivalent to the original code - it checks against `Response<CResponseCode>` not `DataResponse<CResponseCode>`.
Joe Gauterin
@Joe: yes, you're right but check my comments on @Heinzi's answer.
Daniel Renshaw
A: 

I can't imagine to do something with this without finding person responsible for writing this XResponseZZZ. Maybe others are smarter than me. But im convinced that you should find the guy and presuade to him that it should be XResponse responsibility to known if specified code is okay and what error message should be thrown. This is C coding style and it is done bad.

I looked at the Heinzi or Daniel generic solutions and I like them most.

Bart
A: 

Here's a solution with dynamic (can be edited to use reflection instead), untested and not recommended, but short.

It should work identically to your original function:

  • Since you rely on response.GetType() == typeof(XXX), which is not the same as response is XXX (inheritance is excluded), types.Contains(response.GetType()) is equivalent.
  • Since you guarantee that all these types have a property Code which is (presumably) an enum type that contains a value Ok, the dynamic portion should always succeed.
  • The fact that only the eligible types are included means that 'coincidences' cannot happen.

Cons:

  • Performance?
  • If the underlying types change, you will not be protected at compile-time.

private static bool ProcessErrorCode(object response)
{
    var types = new[] { typeof(Response<AResponseCode>), typeof(Response<BResponseCode>), typeof(DataResponse<CResponseCode, string>)};
    var errCode = !types.Contains(response.GetType())
                  ?"UNKNOWN"
                  :(string)(((dynamic)response).Code.ToString());

    if(errCode == "Ok") return true;

    LogErrorCode("Operation resulted in error code:" + errCode);
    return false;
}
Ani
A: 

I would be inclined to try to get the main body of code quite simple like this:

/// <summary>
/// Calls matching process error code on response.Code
/// </summary>
/// <param name="response">Actually will be of type Response or extend it</param>
/// <returns>true for successful response, false otherwise</returns>
private static bool ProcessErrorCode(object response)
{
    Func<Type, Func<object, string>> process = ...;
    var errCode = process(response.GetType())(response);
    if (errCode != "Ok")
    {
        LogErrorCode("Operation resulted in error code:" + errCode);
    }
    return errCode == "Ok";
}

Then it just becomes a matter of defining the Func<Type, Func<object, string>>. This could be done using a separate method or by dependency injection.

The separate method would look like this:

private static Func<Type, Func<object, string>> _process = null;
private static Func<Type, Func<object, string>> GetProcessFunc()
{
    if (_process == null)
    {
        var d = new Dictionary<Type, Func<object, string>>()
        {
            { typeof(Response<AResponseCode>), r => ((Response<AResponseCode>)r).Code.ToString() },
            { typeof(Response<BResponseCode>), r => ((Response<BResponseCode>)r).Code.ToString() },
            { typeof(DataResponse<CResponseCode,string>), r => ((DataResponse<CResponseCode,string>)r).Code.ToString() },
        };
        _process = t =>
        {
            if (d.Contains(t))
            {
                return o => d[t];
            }
            return o => "UNKNOWN";
        };
    }
    return _process;
}

This still has the same code, per se, but it is now better separated and can be replaced with a dependency injection approach more easily. :-)

Enigmativity