Anonymous objects are strongly typed.
The only concern is that you can't know the type name (not directly).
Take this example (sorry if it is too long):
static void T2( )
{
var x = new
{
a = new { a1 = new Type1( "x.1" ), a2 = new Type2( 1 ), a3 = new Type3( '1' ) },
b = new { b1 = new Type1( "x.2" ), b2 = new Type2( 2 ), b3 = new Type3( '2' ) }
};
var y = new
{
a = new { a1 = new Type1( "y.1" ), a2 = new Type2( 1 ), a3 = new Type3( '1' ) },
b = new { b1 = new Type1( "y.2" ), b2 = new Type2( 2 ), b3 = new Type3( '2' ) }
};
var z = new
{
a = new { a1 = new Type1( "y.1" ), a2 = new Type3( '1' ) },
b = new { b1 = new Type3( 'z' ), b2 = new Type2( 2 ) }
};
Console.WriteLine( new string( '-', 40 ) );
Console.WriteLine( "Anonymous object \"x\" is named {0}.", x.GetType( ) );
Console.WriteLine( "Anonymous object \"y\" is named {0}.", y.GetType( ) );
Console.WriteLine( "Anonymous object \"z\" is named {0}.", z.GetType( ) );
Console.WriteLine( new string( '-', 40 ) );
Console.Write( "Anonymous object \"x\" == \"y\"? " );
Console.WriteLine( x.Equals( y ) ? "Yes" : "No" );
Console.Write( "Anonymous object \"x\" == \"z\"? " );
Console.WriteLine( x.Equals( z ) ? "Yes" : "No" );
var x2 = new
{
a = new { a1 = new Type1( "x.1" ), a2 = new Type2( 1 ), a3 = new Type3( '1' ) },
b = new { b1 = new Type1( "x.2" ), b2 = new Type2( 2 ), b3 = new Type3( '2' ) }
};
Console.Write( "Anonymous object \"x\" == \"x2\"? " );
Console.WriteLine( x.Equals( x2 ) ? "Yes" : "No" );
// Uncomment it to give:
//Error 1 Cannot implicitly convert type 'AnonymousType#1' to 'AnonymousType#2'
#if GiveMeAnError
z = new
{
a = new { a1 = new Type1( "z.1" ), a2 = new Type2( 1 ), a3 = new Type3( '1' ) },
b = new { b1 = new Type1( "z.2" ), b2 = new Type2( 2 ), b3 = new Type3( '2' ) }
};
Console.WriteLine( "Anonymous object \"z\" now is named {0}.", z.GetType( ) );
Console.Write( "Anonymous object \"x\" == \"z\"? " );
Console.WriteLine( x.Equals( z ) ? "Yes" : "No" );
#endif
Console.ReadKey( );
}
It outputs:
/*----------------------------------------
Anonymous object "x" is named <>f__AnonymousType2`2[<>f__AnonymousType0`3 [anon_obj.Type1,anon_obj.Type2,anon_obj.Type3],<>f__AnonymousType1`3[anon_obj.Type1,anon_obj.Type2,anon_obj.Type3]].
Anonymous object "y" is named <>f__AnonymousType2`2[<>f__AnonymousType0`3[anon_obj.Type1,anon_obj.Type2,anon_obj.Type3],<>f__AnonymousType1`3[anon_obj.Type1,anon_obj.Type2,anon_obj.Type3]].
Anonymous object "z" is named <>f__AnonymousType2`2[<>f__AnonymousType3`2[anon_obj.Type1,anon_obj.Type3],<>f__AnonymousType4`2[anon_obj.Type3,anon_obj.Type2]].
----------------------------------------
Anonymous object "x" == "y"? No
Anonymous object "x" == "z"? No
Anonymous object "x" == "x2"? Yes*/
Each anonymous object composition has its own name and defines an unique type.
Objects declared with the same types and type names go to the same type, as in "x == x2".
The original example, though, is tricky, as it defines "object[]" arrays with "object[]" arrays inside.
This way
var x = new object[ ]
{
new object[] { new Type1("x.1"), new Type2(1), new Type3('1') },
new object[] { new Type1("x.2"), new Type2(2) , new Type3('2')}
};
var y = new object[ ]
{
new object[] { new Type1("y.1"), new Type2(1), new Type3('1') },
new object[] { new Type1("y.2"), new Type2(2) , new Type3('2')}
};
var z = new object[ ]
{
new object[] { new Type1("y.1"), new Type3('1') },
new object[] { new Type3('z'), new Type2(2)}
};
Will all be the same type (object[]), and the comparison will be allways done by comparing pointers, that will, hopefuly, differ.
static void T1( )
{
var x = new object[ ]
{
new object[] { new Type1("x.1"), new Type2(1), new Type3('1') },
new object[] { new Type1("x.2"), new Type2(2) , new Type3('2')}
};
var y = new object[ ]
{
new object[] { new Type1("y.1"), new Type2(1), new Type3('1') },
new object[] { new Type1("y.2"), new Type2(2) , new Type3('2')}
};
var z = new object[ ]
{
new object[] { new Type1("y.1"), new Type3('1') },
new object[] { new Type3('z'), new Type2(2)}
};
Console.WriteLine( new string( '-', 40 ) );
Console.WriteLine( "Anonymous object \"x\" is named {0}.", x.GetType( ) );
Console.WriteLine( "Anonymous object \"y\" is named {0}.", y.GetType( ) );
Console.WriteLine( "Anonymous object \"z\" is named {0}.", z.GetType( ) );
Console.WriteLine( new string( '-', 40 ) );
Console.Write( "Anonymous object \"x\" == \"y\"? " );
Console.WriteLine( x.Equals( y ) ? "Yes" : "No" );
Console.Write( "Anonymous object \"x\" == \"z\"? " );
Console.WriteLine( x.Equals( z ) ? "Yes" : "No" );
var x2 = new object[ ]
{
new object[] { new Type1("x.1"), new Type2(1), new Type3('1') },
new object[] { new Type1("x.2"), new Type2(2) , new Type3('2')}
};
Console.Write( "Anonymous object \"x\" == \"x2\"? " );
Console.WriteLine( x.Equals( x2 ) ? "Yes" : "No" );
z = new object[ ]
{
new object[] { new Type1("x.1"), new Type2(1), new Type3('1') },
new object[] { new Type1("x.2"), new Type2(2) , new Type3('2')}
};
Console.WriteLine( "Anonymous object \"z\" now is named {0}.", z.GetType( ) );
Console.Write( "Anonymous object \"x\" == \"z\"? " );
Console.WriteLine( x.Equals( z ) ? "Yes" : "No" );
Console.Write( "Anonymous object \"x\" == \"z\" (memberwise)? " );
Console.WriteLine(
x[ 0 ].Equals( z[ 0 ] )
&& x[ 1 ].Equals( z[ 1 ] )
? "Yes" : "No" );
Console.ReadKey( );
}
Will output:
/*----------------------------------------
Anonymous object "x" is named System.Object[].
Anonymous object "y" is named System.Object[].
Anonymous object "z" is named System.Object[].
----------------------------------------
Anonymous object "x" == "y"? No
Anonymous object "x" == "z"? No
Anonymous object "x" == "x2"? No
Anonymous object "z" now is named System.Object[].
Anonymous object "x" == "z"? No
Anonymous object "x" == "z" (memberwise)? No
----------------------------------------*/
See the gotcha?