我一直在为我正在开发的程序整理审计解决方案,我正在使用LINQ进行更新/插入操作。我提出了以下解决方案(这是用于插入的代码段)(注意,Tables变量包含已修改的所有表的列表 - 我手动将这些表添加到列表中并调用此方法):
BindingFlags b = BindingFlags.Instance | BindingFlags.Public;
LINQDataContext dc = new LINQDataContext();
foreach (object Table in Tables)
{
string TableName = Table.ToString().Replace("Project.", "");
switch (TableName)
{
case "Job":
string NewJobString = null;
Job JobDetails = (Job)Table;
var prpsJob = typeof(Job).GetProperties(b);
foreach (var p in prpsJob)
{
object x = p.GetGetMethod().Invoke(JobDetails, null);
x = StripDate(x);
NewJobString += p.Name + ": " + x + Environment.NewLine;
}
Audit(JobID, NewJobString, "New Job created", SourceID, "", JobDetails.JobID);
break;
case "Estimation":
string NewEstimationsString = null;
Estimation EstimationDetails = (Estimation)Table;
var prpsEstimations = typeof(Estimation).GetProperties(b);
foreach (var p in prpsEstimations)
{
object x = p.GetGetMethod().Invoke(EstimationDetails, null);
x = StripDate(x);
NewEstimationsString += p.Name + ": " + x + Environment.NewLine;
}
Audit(JobID, NewEstimationsString, "New Estimation created", SourceID, "", EstimationDetails.EstimationID);
break;
代码继续为每个可能的表名。代码工作正常,但效果似乎相当低 - 每个案例都有一个几乎相同的块。有更有效的方法吗?
答案 0 :(得分:2)
您应该能够使用Lambdas来覆盖重复代码的类型特定部分。这是我一起乱砍的一些伪代码....
void TableIsJob(Job j, BindingFlags b) {
HandleTable("Job", j.JobID, typeof(Job).GetProperties(b),
p=>p.GetGetMethod().Invoke(j, null));
}
void TableIsEstimation(Estimation e, BindingFlags b) {
HandleTable("Estimation", e.EstimationID, typeof(Estimation).GetProperties(b),
p => p.GetGetMethod().Invoke(e, null));
}
void HandleTable(string nm, int ID, PropertyInfo [] props, Func<PropertyInf, Object> i) {
string desc = string.Join(Environment.NewLine, props.Select(p=>{
return string.Format("{0}: {1}", p.Name,
StripDate(i(p)));
}).ToArray());
Audit(JobID, desc, string.Format("New {0} created", nm),
SourceID, "", id);
}
然后你可以用...替换你的庞大的for循环和切换案例。
Tables.Select(t =>
{
switch (t.ToString().Replace("Project.", ""))
{
case "Job":
TableIsJob((Job)t, b);
break;
case "Estimation":
TableIsEstimation((Estimation)t, b);
break;
}
});
这都假设“有效”意味着代码量,而不是执行时间。
答案 1 :(得分:0)
嗯,您当然可以将以下代码转换为方法:
string NewJobString = null;
Job JobDetails = (Job)Table;
var prpsJob = typeof(Job).GetProperties(b);
foreach (var p in prpsJob)
{
object x = p.GetGetMethod().Invoke(Table, null);
x = StripDate(x);
NewJobString += p.Name + ": " + x + Environment.NewLine;
}
public string GetProperties(Type t, BindingFlags b)
{
StringBuilder sb = new StringBuilder();
var prpsJob = typeof(t).GetProperties(b);
foreach (var p in prpsJob)
{
object x = p.GetMethod().Invoke(Table, null);
x = StripDate(x);
sb.Append(p.Name + ": " + x + Environment.NewLine);
}
return sb.ToString()
}
有类似
的东西 case "Job":
Audit(JobID, GetProperties(typeof(Job),b), "New Job created", SourceID, "", JobDetails.JobID);
break;
答案 2 :(得分:0)
从我可以收集的内容来看,大多数重复的代码都是将对象的值转换为字符串。
您可以使用辅助方法执行此操作:
public static string DumpObject<T>(T obj)
{
StringBuilder sb = new StringBuilder();
var properties = typeof(T).GetProperties(
BindingFlags.Instance | BindingFlags.Public);
foreach (var p in properties)
{
object x = p.GetGetMethod().Invoke(obj, null);
x = StripDate(x);
sb.Append(p.Name).Append(": ").Append(x).AppendLine();
}
return sb.ToString();
}
就执行时间而言,这仍然不是非常有效的代码,但它会减少代码重复。我还改变了追加使用StringBuilder的字符串。在这种情况下,这只是一种很好的做法。
顺便说一句,对于局部变量和参数使用驼峰大小写是惯例:
switch (tableName)
{
case "Job":
Job jobDetails = (Job)table;
Audit(jobID, DumpObject(jobDetails), "New Job created",
sourceID, "", jobDetails.JobID);
break;
// ...
}
答案 3 :(得分:0)
我建议您使用T4模板,使用LINQ to SQL templates for T4生成LINQ to SQL类。然后在有特殊需求的表上添加一个接口。
public interface IHaveEstimation {
DateTime GetEstimationDate();
}
在LINQDataContext.tt文件中,您可以添加一些额外的T4生成代码来检测表并将接口添加到该对象:
<#
string markerInterface = String.Empty;
if (class1.Name == "Estimation")
{
markerInterface = "IHaveEstimation";
}
#>
<#=code.Format(class1.TypeAttributes)#>partial class <#=class1.Name#>
<#=String.IsNullOrEmpty(markerInterface) ? String.Empty : String.Format(" : {0}", markerInterface) #>
{ ... }
在LINQDataContext.cs文件中,您可以执行以下操作:
/// <summary>
/// When the database context is submitted.
/// </summary>
/// <param name="failureMode">
/// the submit failure mode
/// </param>
public override void SubmitChanges(ConflictMode failureMode)
{
foreach (var insert in changeSet.Inserts.OfType<IHaveEstimation>())
{
var estimtation = insert.GetEstimationDate();
// handle auditing, etc.
}
// do same for update and delete change sets
}
答案 4 :(得分:0)
你应该真的使用这个答案from SO quesetion
如果您不想序列化所有属性,我强烈建议您创建自定义属性并根据它过滤列表(当然先修改属性)。与IL混淆在开始时很脏,但它是最有效的方法。把手放下。
路