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

获取完整的对象图字符串C#,c#,reflection,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 S

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

示例代码:

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]
       }
只维护计数器是可能的(而且可能更有效):

但我想知道这是否可能与C#反射有关?我需要在多个类中使用它,因此最好将对象传递给方法并返回对象图,完全动态:

var resultOne = GetViaReflection(discount);
// returns: allSales[1].sale.orders.detail.discounts[0]
var resultTwo = GetViaReflection(currentAnimal);
// returns: animals[3].animal.types[2]
使用常规for循环? 我不知道
allSales
sale.orders.detail.折扣的类型,但我认为可以安全地假设它们至少是
IEnumerable

List
将从
IEnumerable

//如果将IEnumerable包装在列表中,则可以访问索引器并计数
var allSalesList=新列表(allSales);
for(int i=0;i
我只是想一想,但我认为这不可能以你现在的想法实现

我有一段时间在寻找方法名。这里的优点是我可以返回调用堆栈,但我不相信有任何东西像对象层次结构的调用堆栈。对象根本不知道有引用的其他对象的任何信息。例如:

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?
}
公共A类{
公共列表对象{get;set;}
}
公共B级{
公共B(int i){}
//废话
}
公共静态void Main(字符串[]args)
{
//建立一个简单的对象库
//根:A
/*
A.
|-B1
|-B2
|-B3
*/
var alpha=新的A()
{
对象=新列表()
{
新B(1),,
新B(2),,
新的B(3)
}
}
//MagicMethod(object objectToTrace)是我们正在寻找的神秘方法
//你要找的是这样的东西:
MagicMethod(alpha.Objects[1]);//应输出“alpha.Objects[1]”
//但是,如果我们对同一个对象进行另一次引用,会怎么样?
var beta=α对象[1];
//那么MagicMethod()会产生什么结果呢?
MagicMethod(beta);//必须生成“beta”
//当我们调用MagicMethod()时
//基本上相同的论点,我们得到两种不同的结果?
}
如您所见,我们的
MagicMethod()
不可能知道应该打印哪个引用。因此,即使一个对象有一个记录,记录了对其自身的引用所在的所有位置,它也不可能选择正确的位置


我希望我能把我的想法传达给你。我想在这里说:我不知道这是否是真的,但我无法想象这是真的。

如果我们撇开一个显而易见的问题,即
所有销售
都可能发生变化,使索引在一秒钟内毫无用处

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 }]"

foreach
隐藏了一个枚举数,所以我猜你运气不好。对象没有索引。。。(或者父级或存储它们的数组IEnumerable也没有搜索的概念)。因此,不太清楚您希望如何使用反射来查找不存在的内容。
allSales
sale.orders.detail.discounters
的类型是什么?与其说索引。。。它也是对象路径。我将在多个位置需要此功能,因此如果我可以传递GetViaReflection(折扣),它返回“allSales[1].sale.orders.detail.Deploys[0]”或GetViaReflection(DifferentitoObject),那就太好了。避免对对象图部分进行硬编码。是的,全部为IEnumerable。见我的问题编辑,我进一步澄清,这将是重用的目标。谢谢我刚看到,在我点击提交!好吧。我认为这回答了你最初的问题,但这种情况(涉及反思)可能会出现在其他人的答案中。你的答案是最简单的方法。我受到了FluentValidation库的启发,想要重新创建它。事实证明,它建立了一个“财产链”,在向下发展的过程中不断积累。本质上:一些反射,但没有神奇的子弹。
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}]"));
...
.Select(sdi=>$"allSales[{sdi.SaleId}].sale.orders.detail.discounts[{sdi.DiscountId }]"