使用反射从C#对象中剥离所有值

5
我有以下方法,使用反射从对象中检索所有值作为字符串。对象可以包含其中的可枚举值,我也想检索这些值。还需要考虑忽略字段列表,以便不返回这些字段的值。
public static IEnumerable<string> StringContent(this object obj, IEnumerable<string> ignoreProperties = null)
{
    Type t = obj.GetType();
    foreach (var prop in t.GetProperties())
    {
        if (ignoreProperties != null && ignoreProperties.Contains(field.Name))
        {
            continue;
        }
        var value = prop.GetValue(obj);
        if (value != null)
        {
            if (value is IEnumerable<object>)
            {
                foreach (var item in (IEnumerable<object>)value)
                {
                    foreach (var subValue in item.StringContent())
                    {
                        yield return subValue.ToString();
                    }
                }
            }
            else
            {
                yield return value.ToString();
            }
        }
    }
}

这个方法完美地工作并给出了正确的结果。然而,由于它要被执行很多次,我需要尽可能加速它。

有人有什么建议吗?

提前感谢!

**编辑**

示例测试用例:

[TestMethod]
public void StringContent()
{
    Project project = projectA;
    List<string> ignoreFields = new List<string>() { "SalesEngineer", "CreationDate" };
    var result = project.StringContent(ignoreFields);
    Assert.IsTrue(result.Count() == 26);
}

项目对象:

public class Project : IEntity
{
    public Project()
    {
        Products = new List<ProjectProducts>();
    }

    public int Id { get; set; }
    public DateTime CreationDate { get; set; }
    public string SalesEngineer { get; set; }
    public string SalesEngineerEmail { get; set; }
    public int? TeamId { get; set; }
    public string Name { get; set; }
    public string City { get; set; }
    public string Originator { get; set; }
    public string ContactName { get; set; }
    public string MainClient { get; set; }
    public string Contractor { get; set; }
    public string ContractorContactName { get; set; }
    public string ContractorLocation { get; set; }
    public string Wholesaler { get; set; }
    public string WholesalerContactName { get; set; }
    public string WholesalerLocation { get; set; }
    public float EstimatedValue { get; set; }
    public float CalculatedValue { 
        get { return EstimatedValue/Convert.ToSingle(Currency != null ? Currency.Rate : (decimal)1.0); }
    }
    public int Probability { get; set; }
    public int SectorId { get; set; }
    public int TypeId { get; set; }
    public string StatusCode { get; set; }
    public string LostTo { get; set; }
    public int ReasonId { get; set; }
    public string SecondaryEngineer { get; set; }
    public float SplitPercentage { get; set; }
    public DateTime ExpectedOrder { get; set; }
    public DateTime? RequiredOnSiteBy { get; set; }
    public bool LightingDesignRequired { get; set; }
    public string ReasonForLightingDesign { get; set; }
    public DateTime? DesignRequiredBy { get; set; }
    public DateTime? FollowUp { get; set; }
    public string Comments { get; set; }
    public int CurrencyId { get; set; }
    public bool Void { get; set; }
    public string AttachmentFolder { get; set; }

    public virtual Currency Currency { get; set; }
    public virtual Reason Reason { get; set; }
    public virtual ProjectStatus Status { get; set; }
    public virtual ProjectType Type { get; set; }
    public virtual Sector Sector { get; set; }
    public virtual ICollection<ProjectProducts> Products { get; set; }
    public virtual Team Team { get; set; }

    public object Key
    {
        get { return Id; }
    }

}

我会做的第一件事是在代码中将“field”重命名为“property”,因为你根本不需要查找字段。显然,这不会加快任何速度,但它会提高代码的清晰度。现在,当前性能如何?你需要什么样的性能?你能提供基准测试的例子吗?(如果你还没有进行基准测试,那就是下一步要做的事情...) - Jon Skeet
你应该使用 Reflection.Emit 或 System.Linq.Expressions.Lambda 来生成动态委托,以便减少性能开销。我会在稍后详细回答这个问题。 - Oleh Nechytailo
您可能还想查看 https://github.com/mgravell/fast-member。 - Jon Skeet
我将在一个隔离的测试案例上进行工作以提供。我说得尽可能低,因为我不确定性能成本的现实期望应该是什么,因此我要求一般性的改进,而不是需要它使用5%的CPU等。这些对象是相当复杂的对象,我可以提供一个示例。目前只有两个属性被排除在外。正如您从方法签名中所看到的,ignoreFields的类型是IEnumerable<string>()。 - DaRoGa
是的,我可以告诉声明类型,但如果有100个属性被忽略,传入HashSet<string>LinkedList<string>之间会有很大的区别。执行时类型很重要。 - Jon Skeet
显示剩余12条评论
1个回答

2
您可以使用stringify软件包。
它存在于Nuget中。
您可以使用Hidden属性隐藏参数。
您可以使用a.stringify();打印每个对象。

你能给一个例子吗? - DaRoGa
安装了这个NuGet包之后,你可以使用.stringify()函数打印出每个对象。 - Ygalbel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接