2011-08-11 177 views
3

我无法将一个匿名类型转换为另一个匿名类型。我想知道为什么。无法将一个匿名类型转换为另一个匿名类型

public static class Class1{ 
    public static object GetFinance(Guid contractB2CId) 
    { 
     return new 
     { 
     Item1 = reader.ValueOrDefault<decimal>(0), 
     Item2 = reader.ValueOrDefault<decimal>(1), 
     Item3 = reader.ValueOrDefault<decimal>(2), 
     Item4 = reader.ValueOrDefault<decimal>(3), 
     Item5 = reader.ValueOrDefault<decimal>(4), 
     Item6 = reader.ValueOrDefault<decimal>(5) 
     }; 
    } 


    object obj = GetFinance(); 
    var financeInfo = obj.UnsafeCast(new 
     { 
      Item1 = default(decimal), 
      Item2 = default(decimal), 
      Item3 = default(decimal), 
      Item4 = default(decimal), 
      Item5 = default(decimal), 
      Item6 = default(decimal) 


     }); 

} 

    public static class Class2{            
    public static T UnsafeCast<T>(this object obj, T type) 
    { 
     return (T) obj; 
    } 
} 

异常

无法转换 类型“<> f__AnonymousType1 6[System.Decimal,System.Decimal,System.Decimal,System.Decimal,System.Decimal,System.Decimal]' to type '<>f__AnonymousType0 6 [System.Decimal,System.Decimal,System.Decimal,System.Decimal,System.Decimal,系统的目的.Decimal]”。

enter image description here

UPDATE: 有什么办法避免这种例外,除了使用Tuple<decimal.....>或使用一个组装?

回答

7

匿名类型绑定到它们声明的程序集(技术上,模块)。我的猜测是这个代码在不同的程序集中。因此,它们是完全不同的类型,看起来相似。

请注意,动态生成的代码(ASP.NET页面等)将在不同的程序集中。

顺便说一下,这个技巧被称为“通过示例进行投射”,只要类型在同一个程序集中,它就能正常工作(只是测试了它)。

这是工作,因为都是在一个装配:

static class Program 
{ 
    static void Main() 
    { 
     object obj = GetFinance(); 
     var financeInfo = obj.UnsafeCast(new 
     { 
      Item1 = default(decimal), Item2 = default(decimal), 
      Item3 = default(decimal), Item4 = default(decimal), 
      Item5 = default(decimal), Item6 = default(decimal) 
     }); 
     System.Console.WriteLine(financeInfo.Item3); // 76 
    } 
    public static object GetFinance() 
    { 
     decimal x = 76; 
     return new 
     { 
      Item1 = x, Item2 = x, Item3 = x, 
      Item4 = x, Item5 = x, Item6 = x 
     }; 
    } 

    public static T UnsafeCast<T>(this object obj, T type) 
    { 
     return (T)obj; 
    } 
} 
+0

我的代码位于不同的程序集中。我认为这是例外的原因。 – Alexandre

+0

如果这些类型在同一个程序集中,那么这个类型是多余的,所以是的。但是,除非你正在施放对象或其他重复施放(施放为相同类型),否则使用匿名类型施放时将失去运气 –

+1

@Alex如果它位于不同的装配体中,则我知道***它是原因。匿名类型的类型等价只适用于同一个程序集。考虑使用一个命名类型 - 也许是'Tuple.Create(...)'等 –

2

正如您从错误消息中可以看出的那样,编译器已经生成了2种不同的类型。 f__AnonymousType1f__AnonymousType0。他们没有任何关系。

它们包含(完全)相同属性的事实是巧合,编译器不会在两个“相同”类型之间进行投射。他们必须是相关的。

同样的问题,而匿名类型:

class A1 
{ 
    public int Id { get; set; } 
} 

class A2 
{ 
    public int Id { get; set; } 
} 


    A1 a = new A1(); 
    A2 b = (A2) a; // error 

错误1无法将类型 'MyApp.A1' 到 'MyApp.A2'

但是,如果你使用的是C#4 ,请看看Tuple<T1,T2,T3,T4,T5,T6>。它应该让你做同样的事情,或者至少类似的事情。

+0

在语言规范它完全阐明,两个匿名类型在同一顺序相同的名称和类型的*会*同类型,除非(请参阅我的回答); p –

+1

不,我不同意;这是一个**不同的问题。在某些限制下,Cast-by-example可以正常工作。这不是一个好主意,但它有效。 –

+0

好的,我没有调查_why_他们是不同的类型。你可能对不同的程序集是正确的。 –

0

这在技术上是完全2单独的类。你不能只在两个班级之间施放,因为他们彼此相像。对于这种语言,尝试将double转换为button同样不可能。 如果你使用c#4.0,我会建议使用通用的Tuple类,使所有的输入。 如果不是,请编写您自己的小班使用。

+0

如果它们在同一个程序集***中它们将是***相同的类型(在C#规范中有保证) - 期望在这里不是不合理的,只是其中一个注意事项没有满足。 –

1

如果你看看异常,你会看到它们是两种不同的类型。一个不来自另一个。

规格说:

An anonymous type is a nameless class type that inherits directly from object An anonymous type is a nameless class type that inherits directly from object. The members of an anonymous type are a sequence of read/write properties inferred from the object initializer(s) used to create instances of the type. Specifically. Within the same program, two anonymous object initializers that specify a sequence of properties of the same names and types in the same order will produce instances of the same anonymous type

从你有不同类型,无论从对象得到错误信息作出。那么为什么你会期望能够从一个到另一个?

,如果你有

class foo<T1,T2,T3,T4,T5,T6>{ 
T1 Item1 
T2 Item2 
T3 Item3 
T4 Item4 
T5 Item5 
T6 Item6 
} 

class Bar<T1,T2,T3,T4,T5,T6>{ 
T1 Item1 
T2 Item2 
T3 Item3 
T4 Item4 
T5 Item5 
T6 Item6 
} 

你会也希望能够这两个之间的投?

唯一的区别是类型的名称。矿被称为Foo和Bar你<> F_ AnonymousType1和<>˚F _AnonymousType0

+1

“你为什么这么认为......” - 因为语言规范正式声明(在一定的范围内),这可以保证工作。期望不是没有道理的 - 简而言之,这些限制并未得到满足。 –

+1

@Marc Gravel你可能是对的,因为我记得他们说的规格说明,在特定的范围内,生成的类型将不会相互衍生或相互转换。我记得不正确如果你有的话,我会喜欢这个规范的参考。在这个假设看到这两种类型是不一样的(当然这将使“铸造”成为可能)我说我的问题 –

+0

以及这很接近:http://msdn.microsoft.com/en-us/library/ ms364047(v = vs.80).aspx#cs3spec_topic6“在同一个程序中,两个匿名对象初始值设定项指定相同名称和类型的相同顺序的属性序列将产生相同匿名类型的实例。包括属性的顺序,因为它在某些情况下是可观察的和重要的,如反射。)“ - 虽然这不是规范文档,在现实中,“程序”应该读作“程序集” –