C# 减少铸造和更好的造型

C# 减少铸造和更好的造型,c#,coding-style,casting,C#,Coding Style,Casting,考虑以下(令人讨厌的)代码: // ///在响应时调用匹配的进程错误代码。代码 /// ///实际上将是响应类型或扩展类型 ///如果响应成功,则为true,否则为false 私有静态布尔ProcessErrorCode(对象响应) { bool-isOkay=false; 常量字符串unknown=“unknown”; 字符串errCode=未知; if(response.GetType()==typeof(response)) { AResponseCode代码=((响应)响应).code

考虑以下(令人讨厌的)代码:

//
///在响应时调用匹配的进程错误代码。代码
/// 
///实际上将是响应类型或扩展类型
///如果响应成功,则为true,否则为false
私有静态布尔ProcessErrorCode(对象响应)
{
bool-isOkay=false;
常量字符串unknown=“unknown”;
字符串errCode=未知;
if(response.GetType()==typeof(response))
{
AResponseCode代码=((响应)响应).code;
isOkay=code==AResponseCode.Ok;
errCode=code.ToString();
}
if(response.GetType()==typeof(response))
{
BResponseCode代码=((响应)响应).code;
isOkay=code==BResponseCode.Ok;
errCode=code.ToString();
}
if(response.GetType()==typeof(DataResponse))
{
CResponseCode代码=((数据响应)响应)。代码;
isOkay=code==CResponseCode.Ok;
errCode=code.ToString();
}
if(isOkay)
{
返回true;
}
string msg=“操作导致错误代码:”+errCode;
日志错误代码(msg);
返回false;
}
我正试图找出一种减少铸件和改进方法风格的方法。 我对
Response
DataResponse
AResponseCode
BResponseCode
responsecode

响应参数的类型为
response
或从中继承(
DataResponse:response


所有
*ResponseCode
都是枚举,它们都有一个
*ResponseCode.Ok
条目我想为所有ifs交换一个switch语句。

理想情况下,您应该给
Response
一个带有“Ok”函数的公共接口。既然你做不到,你的解决方案看起来会有点粗糙


考虑到这一限制,我将提取两种方法-
静态bool IsResponseOk(对象响应)
静态字符串GetResponseError(对象响应)
——这将使代码更易于阅读,但仍然不够出色。

这取代了我以前的答案,因为它明显地轰炸了:)(它们是中断)

我不认为这会做得更好,但你可能会发现这种方法很有趣

基本思想是定义一个包含IsOkay和ErrCode值的结果类型,然后定义一个委托字典(由委托处理的对象类型键入),供您参考。要添加新的处理程序,只需将另一个委托添加到字典中

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()
        };
      });
  }
}
公共类响应结果{
公共图书馆;
公共字符串错误代码;
}
公共静态类响应抽取器
{
//从这里开始使用新版本的方法
公共静态布尔ProcessErrorCode(对象响应)
{
Func处理器=null;
ResponseResult结果=新ResponseResult()
{ 
IsOkay=false,ErrCode=“未知”
};
//尝试根据对象的类型获取处理器
//如果我们找到了,就调用它。
if(_processors.TryGetValue(response.GetType(),out processor))
结果=处理器(响应);
if(result.IsOkay)
返回true;
string msg=“操作导致错误代码:”+result.ErrCode;
日志错误代码(msg);
返回false;
}
//好多了不?
//现在是基础设施
静态字典处理器
=新字典();
静态响应提取程序()
{
//这可以用方法上的自反射来代替
//具有引用支持的类型的属性
//每种方法。
_处理器。添加(类型(响应),(o)=>
{
AResponseCode代码=((响应)o).code;
返回新的响应结果
{
IsOkay=code==AResponseCode.Ok,
ErrCode=code.ToString()
};
});
_处理器。添加(类型(响应),(o)=>
{
BResponseCode代码=((响应)o).code;
返回新的响应结果
{
IsOkay=code==BResponseCode.Ok,
ErrCode=code.ToString()
};
});
_处理器。添加(类型)(数据响应),
(o) =>
{
CResponseCode代码=((数据响应)o).code;
返回新的响应结果
{
IsOkay=code==CResponseCode.Ok,
ErrCode=code.ToString()
};
});
}
}

从性能上看,它比看起来的要好,因为
字典实际上是对支持类型类型句柄的整数值进行哈希运算。这实际上是一个Int64-因此只使用前32位,但实际上,两种类型不太可能共享其句柄的前32位。

从性能角度来看,我将用
is
运算符替换
.GetType()==typeof()
,例如:

if( response is DataResponse<CResponseCode,string> )
if(响应为DataResponse)
以下基准测试显示,在我的机器上,性能提高了大约3倍:

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
var f=新列表();
虚拟变量=0;
秒表sw=新秒表();
sw.Start();
对于(int i=0;i
您可以为此使用通用子例程:

    // 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;
        }
    }
//模拟您的类,只是为了检查它是否编译。你不需要这个。
类响应{
公共T代码{get{返回默认值(T);}
}
枚举AResponseCode{Ok}
枚举BResponseCode{Ok}
枚举对应代码{Ok}
静态无效LogErrorCode(字符串msg){}
私有静态布尔ProcessErrorCode(对象响应)
{
布尔·伊索凯;
字符串错误代码;
if(!TryProcessErrorCode(响应,AResponseCode.Ok,out isOkay,out errCode))
如果(!TryProcessErrorCode)(响应,BRespon
    // 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;
        }
    }
  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;
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;
} 
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;
}
/// <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";
}
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;
}