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;
}