我能以任何方式使这段代码更清洁/更高效吗? (C#/ LINQ到SQL)

时间:2011-03-07 14:29:18

标签: c# asp.net linq-to-sql

我一直在为我正在开发的程序整理审计解决方案,我正在使用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;

代码继续为每个可能的表名。代码工作正常,但效果似乎相当低 - 每个案例都有一个几乎相同的块。有更有效的方法吗?

5 个答案:

答案 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混淆在开始时很脏,但它是最有效的方法。把手放下。