为什么这两个匿名类型不一样?

Why are these two anonymous types not the same?

谁能告诉我为什么这两个匿名类型不一样?

{Name = "<>f__AnonymousType0`6" FullName = "<>f__AnonymousType0`6[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Decimal, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}

{Name = "<>f__AnonymousType0#1`6" FullName = "<>f__AnonymousType0#1`6[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Decimal, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Double, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"}

澄清:(我不知道这是否重要,但一种匿名类型有一个 # 符号。哦,#01)

我有这两段代码。在同一个 class(程序集)中。一个 return 是上面的匿名类型之一,另一个 return 是另一个。但是,两者都在评估相同的表达式。

我已经完成了下面的比较(有些只是为了查看结果,尽管有些应该是正确的 return 错误)。但是,它们都是 return 错误的。 (我可能遗漏了一些我试过的)

ms returns 一种匿名类型。 resultOfSelect returns 另一种匿名类型。

注意:第二段代码中的 methodArgumentStringContainingSelectStatement 包含与字符串相同的表达式。


'ms == resultOfSelect'

'ms.GetType() == resultOfSelect'

'ms.GetType().Equals(resultOfSelect.GetType())'

'ms.GetType() == resultOfSelect.GetType()'

还有其他人。全错

resultOfSelect debugView 是:

{Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<<>f__AnonymousType0#1>}

ms debugView 是:

{Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<<>f__AnonymousType0>}

第一个声明:

   ' var ms =     (instanceContainingSelectMethod as IQueryable<Emar>).Select( nextEmarClassInstanceFromPreviousSelectMany => new { Schedule = nextEmarClassInstanceFromPreviousSelectMany.BEmem.Category.Substring(0, 1), Category = "0" + nextEmarClassInstanceFromPreviousSelectMany.BEmem.Category.Substring(1), Description = "", Year = nextEmarClassInstanceFromPreviousSelectMany.Month.Year, Time = nextEmarClassInstanceFromPreviousSelectMany.Actual_Time, Units = ((nextEmarClassInstanceFromPreviousSelectMany.BEmem.PurchDate ?? nextEmarClassInstanceFromPreviousSelectMany.BEmem.InServiceDate).Value.Year == nextEmarClassInstanceFromPreviousSelectMany.Month.Year)
? (nextEmarClassInstanceFromPreviousSelectMany.BEmem.SoldDate != null)
    ? (nextEmarClassInstanceFromPreviousSelectMany.BEmem.SoldDate.Value.Year == nextEmarClassInstanceFromPreviousSelectMany.Month.Year)
        ? (((12d - ((double)((nextEmarClassInstanceFromPreviousSelectMany.BEmem.PurchDate != null)
            ? (System.DateTime?)nextEmarClassInstanceFromPreviousSelectMany.BEmem.PurchDate.Value
            : nextEmarClassInstanceFromPreviousSelectMany.BEmem.InServiceDate).Value.Month)) + 1d) - (12d - ((12d - ((double)nextEmarClassInstanceFromPreviousSelectMany.BEmem.SoldDate.Value.Month)) + 1d))) / 12d
        : ((12d - ((double)(nextEmarClassInstanceFromPreviousSelectMany.BEmem.PurchDate ?? nextEmarClassInstanceFromPreviousSelectMany.BEmem.InServiceDate).Value.Month)) + 1d) / 12d
    : ((12d - ((double)(nextEmarClassInstanceFromPreviousSelectMany.BEmem.PurchDate ?? nextEmarClassInstanceFromPreviousSelectMany.BEmem.InServiceDate).Value.Month)) + 1d) / 12d
: (nextEmarClassInstanceFromPreviousSelectMany.BEmem.SoldDate != null)
    ? (nextEmarClassInstanceFromPreviousSelectMany.BEmem.SoldDate.Value.Year == nextEmarClassInstanceFromPreviousSelectMany.Month.Year)
        ? (12d - ((12d - ((double)nextEmarClassInstanceFromPreviousSelectMany.BEmem.SoldDate.Value.Month)) + 1d)) / 12d
        : 1d
    : 1d } );'

第二条语句:

            'Func<IQueryable<Emar>, object> customSelectManyDelegate =

           await CSharpScript
             .EvaluateAsync<Func<IQueryable<Emar>, object>>(methodArgumentStringContainingSelectStatement, options);

         resultOfSelect =  customSelectManyDelegate(instanceContainingSelectMethod as IQueryable<Emar>);'

匿名类型实际上只适用于单个方法的上下文,或者可能在某些仅形状重要而不是类型重要的反射场景中。

所以:问为什么类型不同已经破坏了语言特性的意图。至于 为什么 它们是不同的:可能是不同的程序集或模块。这尤其适用于视图编译晚于主代码的 Web 项目。

但是:基本上不要依赖这种平等。不能保证。如果您关心类型是什么(以及它等于什么),那么您的选项包括:

  • 声明您自己的正式类型并使用它 - 最佳选择
  • 使用值元组(ValueTuple<...>,但具有第一种class语言支持,包括从被调用者传播到调用者而不是从调用者传播到被调用者的伪名称)
  • 使用元组 (Tuple<...>)

使用匿名类型并没有真正出现在列表中。

马特·沃伦写了这条评论:

You are using CSharpScript.EvaluateAsync. Each evaluation in C# script is logically its own assembly. Anonymous types are (by implementation not specification) unique per assembly. – Matt Warren Mar 8 '19 at 19:17