获取完整对象图字符串C#

时间:2015-12-02 00:40:09

标签: c# reflection

我正在遍历各种集合,如果满足特定的错误条件,那么我需要完整的对象图,即哪个索引有问题。

示例代码:

foreach (var sale in allSales) {
   foreach (var discount in sale.orders.detail.discounts) {
       if (errorConditionMet) {
          // print full object graph. For example, perhaps it's the second Sale (index one), but first discount object (index zero):
          // We have "discount" object, but want to print: 
          // allSales[1].sale.orders.detail.discounts[0]
       }

可以只维护计数器(并且可能更高效):

    string.Format("allSales[{0}].sale.orders.detail.discounts[{1}]", saleCount, discountCount); 
    // prints: allSales[1].sale.orders.detail.discounts[0]

但我想知道C#Reflection是否可以实现这一目标?我需要在多个类中使用它,所以将对象传递给方法并返回完全动态的对象图会很棒:

var resultOne = GetViaReflection(discount);
// returns: allSales[1].sale.orders.detail.discounts[0]
var resultTwo = GetViaReflection(currentAnimal);
// returns: animals[3].animal.types[2]

3 个答案:

答案 0 :(得分:1)

使用常规for循环? 我不知道allSalessale.orders.detail.discounts的类型,但我认为可以安全地假设它们至少是IEnumerable<T>

List<T>会从IEnumerable<T>

中获取更多功能
//If I wrap the IEnumerable in a list I get access to an indexer and count
var allSalesList = new List<T>(allSales);
for (int i = 0; i < allSalesList.Count; i++) {
    var sale = allSales[i];

    //If I wrap the IEnumerable in a list I get access to an indexer and count
    var discounts = new List<T>(sale.orders.detail.discounts);


    for (int j = 0; i < discounts.Count; j++) {
        var discount = discounts[j];
        if (errorConditionMet) {
            // print full object graph. For example, perhaps it's the second Sale (index one), but first discount object (index zero):
            // We have "discount" object, but want to print: 
            // allSales[1].sale.orders.detail.discounts[0]


            //Your formatting here. I'm using C# 6 string interpolation, but its basically a string format.
            Console.WriteLine($"allSales[{i}].sale.orders.detail.discounts[{j}]")
        }
    }
}

答案 1 :(得分:1)

考虑到这一点,但我认为这不可能以你的思维方式实现。

我有一段时间SO question similar to this正在寻找方法名称。保存的优点是我可以回到调用堆栈,但我不相信有任何类似于对象层次结构的调用堆栈。对象根本不知道有关引用它们的其他对象的任何信息。例如:

public class A {
    public List<B> Objects { get; set; }
}

public class B {
    public B(int i) { }
    //blah
}

public static void Main(string[] args)
{
    //Establish a simple object Heiarchy
    //Root: A
    /*

    A
    |-B1
    |-B2
    |-B3

    */
    var alpha = new A()
    {
        Objects = new List<B>()
        {
            new B(1),
            new B(2),
            new B(3)
        }
    }

    //MagicMethod<T>(object objectToTrace) is the mythical method that we're looking for

    //What you're looking for is something like this:
    MagicMethod(alpha.Objects[1]); //Should output "alpha.Objects[1]"

    //But what if we make another reference to the same object?

    var beta = alpha.Objects[1];

    //Now what would MagicMethod() produce?
    MagicMethod(beta); //would have to produce "beta"

    //How is it possible that when We've called MagicMethod() with 
    //fundamentally the same argument, we get two different outputs?
}

正如您所看到的,我们的MagicMethod()可能无法知道应该打印哪个参考。因此,即使如果一个对象在所有引用自身的地方都有记录,它也不可能选择正确的。

我希望我能够向你传达我的思路。我会在这里说:我不知道这是不是真的,但我无法想象这可能是真的。

答案 2 :(得分:-1)

如果我们抛开allSales可以改变的明显问题并使索引暂时无效......

var salesWithErrors = allSales.Select((sale,saleIdx =>
  new { Sale = sale, // not really needed for the particular example
        Index = saleIdx,
        DiscountsWithErrors = sale.orders.detail.discounts
           .Select((d,i)=>new { 
              Discount = d,
              Index = i,
           })
           .Where(di=>isErrorConditionMet(d.Discount))
  })
  .Where(saleDiscountErrors => saleDiscountErrors.DiscountsWithErrors.Any())

var results = string.Join(Environment.NewLine,
  salesWithErrors.SelectMany(sde=>sde.DiscountsWithErrors.Select(d=>new{
    SaleId = sde.Sale.Id,
    SaleIndex = sde.Index,
    DiscountId = d.Discount.Id
    DiscountIndex = d.Index
  })
  .Select(sdi=>$"allSales[{sdi.SaleIndex}].sale.orders.detail.discounts[{sdi.DiscountIndex}]"));

您可以(应该)输出更持久的对象ID,而不是在短暂集合中输出索引,而是让您在数据库中找到它们,

...
.Select(sdi=>$"allSales[{sdi.SaleId}].sale.orders.detail.discounts[{sdi.DiscountId }]"