public override void Compile( MethodEmitter emitter )
		{
			bool inverse = false;

			string methodName;

			switch ( m_Operator )
			{
				case StringOperator.Equal:
					methodName = "Equals";
					break;

				case StringOperator.NotEqual:
					methodName = "Equals";
					inverse = true;
					break;

				case StringOperator.Contains:
					methodName = "Contains";
					break;

				case StringOperator.StartsWith:
					methodName = "StartsWith";
					break;

				case StringOperator.EndsWith:
					methodName = "EndsWith";
					break;

				default:
					throw new InvalidOperationException( "Invalid string comparison operator." );
			}

			if ( m_IgnoreCase || methodName == "Equals" )
			{
				Type type = ( m_IgnoreCase ? typeof( Insensitive ) : typeof( String ) );

				emitter.BeginCall(
					type.GetMethod(
						methodName,
						BindingFlags.Public | BindingFlags.Static,
						null,
						new Type[]
						{
							typeof( string ),
							typeof( string )
						},
						null
					)
				);

				emitter.Chain( m_Property );
				m_Value.Load( emitter );

				emitter.FinishCall();
			}
			else
			{
				Label notNull = emitter.CreateLabel();
				Label moveOn = emitter.CreateLabel();

				LocalBuilder temp = emitter.AcquireTemp( m_Property.Type );

				emitter.Chain( m_Property );

				emitter.StoreLocal( temp );
				emitter.LoadLocal( temp );

				emitter.BranchIfTrue( notNull );

				emitter.Load( false );
				emitter.Pop();
				emitter.Branch( moveOn );

				emitter.MarkLabel( notNull );
				emitter.LoadLocal( temp );

				emitter.BeginCall(
					typeof( string ).GetMethod(
						methodName,
						BindingFlags.Public | BindingFlags.Instance,
						null,
						new Type[]
						{
							typeof( string )
						},
						null
					)
				);

				m_Value.Load( emitter );

				emitter.FinishCall();

				emitter.MarkLabel( moveOn );
			}

			if ( m_Not != inverse )
				emitter.LogicalNot();
		}
Esempio n. 2
0
		public static IComparer Compile( AssemblyEmitter assembly, Type objectType, Property[] props )
		{
			TypeBuilder typeBuilder = assembly.DefineType(
					"__distinct",
					TypeAttributes.Public,
					typeof( object )
				);

			#region Constructor
			{
				ConstructorBuilder ctor = typeBuilder.DefineConstructor(
						MethodAttributes.Public,
						CallingConventions.Standard,
						Type.EmptyTypes
					);

				ILGenerator il = ctor.GetILGenerator();

				// : base()
				il.Emit( OpCodes.Ldarg_0 );
				il.Emit( OpCodes.Call, typeof( object ).GetConstructor( Type.EmptyTypes ) );

				// return;
				il.Emit( OpCodes.Ret );
			}
			#endregion

			#region IComparer
			typeBuilder.AddInterfaceImplementation( typeof( IComparer ) );

			MethodBuilder compareMethod;

			#region Compare
			{
				MethodEmitter emitter = new MethodEmitter( typeBuilder );

				emitter.Define(
					/*  name  */ "Compare",
					/*  attr  */ MethodAttributes.Public | MethodAttributes.Virtual,
					/* return */ typeof( int ),
					/* params */ new Type[] { typeof( object ), typeof( object ) } );

				LocalBuilder a = emitter.CreateLocal( objectType );
				LocalBuilder b = emitter.CreateLocal( objectType );

				LocalBuilder v = emitter.CreateLocal( typeof( int ) );

				emitter.LoadArgument( 1 );
				emitter.CastAs( objectType );
				emitter.StoreLocal( a );

				emitter.LoadArgument( 2 );
				emitter.CastAs( objectType );
				emitter.StoreLocal( b );

				emitter.Load( 0 );
				emitter.StoreLocal( v );

				Label end = emitter.CreateLabel();

				for ( int i = 0; i < props.Length; ++i )
				{
					if ( i > 0 )
					{
						emitter.LoadLocal( v );
						emitter.BranchIfTrue( end ); // if ( v != 0 ) return v;
					}

					Property prop = props[i];

					emitter.LoadLocal( a );
					emitter.Chain( prop );

					bool couldCompare =
					emitter.CompareTo( 1, delegate()
					{
						emitter.LoadLocal( b );
						emitter.Chain( prop );
					} );

					if ( !couldCompare )
						throw new InvalidOperationException( "Property is not comparable." );

					emitter.StoreLocal( v );
				}

				emitter.MarkLabel( end );

				emitter.LoadLocal( v );
				emitter.Return();

				typeBuilder.DefineMethodOverride(
						emitter.Method,
						typeof( IComparer ).GetMethod(
							"Compare",
							new Type[]
								{
									typeof( object ),
									typeof( object )
								}
						)
					);

				compareMethod = emitter.Method;
			}
			#endregion
			#endregion

			#region IEqualityComparer
			typeBuilder.AddInterfaceImplementation( typeof( IEqualityComparer<object> ) );

			#region Equals
			{
				MethodEmitter emitter = new MethodEmitter( typeBuilder );

				emitter.Define(
					/*  name  */ "Equals",
					/*  attr  */ MethodAttributes.Public | MethodAttributes.Virtual,
					/* return */ typeof( bool ),
					/* params */ new Type[] { typeof( object ), typeof( object ) } );

				emitter.Generator.Emit( OpCodes.Ldarg_0 );
				emitter.Generator.Emit( OpCodes.Ldarg_1 );
				emitter.Generator.Emit( OpCodes.Ldarg_2 );

				emitter.Generator.Emit( OpCodes.Call, compareMethod );

				emitter.Generator.Emit( OpCodes.Ldc_I4_0 );

				emitter.Generator.Emit( OpCodes.Ceq );

				emitter.Generator.Emit( OpCodes.Ret );

				typeBuilder.DefineMethodOverride(
						emitter.Method,
						typeof( IEqualityComparer<object> ).GetMethod(
							"Equals",
							new Type[]
							{
								typeof( object ),
								typeof( object )
							}
						)
					);
			}
			#endregion

			#region GetHashCode
			{
				MethodEmitter emitter = new MethodEmitter( typeBuilder );

				emitter.Define(
					/*  name  */ "GetHashCode",
					/*  attr  */ MethodAttributes.Public | MethodAttributes.Virtual,
					/* return */ typeof( int ),
					/* params */ new Type[] { typeof( object ) } );

				LocalBuilder obj = emitter.CreateLocal( objectType );

				emitter.LoadArgument( 1 );
				emitter.CastAs( objectType );
				emitter.StoreLocal( obj );

				for ( int i = 0; i < props.Length; ++i )
				{
					Property prop = props[i];

					emitter.LoadLocal( obj );
					emitter.Chain( prop );

					Type active = emitter.Active;

					MethodInfo getHashCode = active.GetMethod( "GetHashCode", Type.EmptyTypes );

					if ( getHashCode == null )
						getHashCode = typeof( object ).GetMethod( "GetHashCode", Type.EmptyTypes );

					if ( active != typeof( int ) )
					{
						if ( !active.IsValueType )
						{
							LocalBuilder value = emitter.AcquireTemp( active );

							Label valueNotNull = emitter.CreateLabel();
							Label done = emitter.CreateLabel();

							emitter.StoreLocal( value );
							emitter.LoadLocal( value );

							emitter.BranchIfTrue( valueNotNull );

							emitter.Load( 0 );
							emitter.Pop( typeof( int ) );

							emitter.Branch( done );

							emitter.MarkLabel( valueNotNull );

							emitter.LoadLocal( value );
							emitter.Call( getHashCode );

							emitter.ReleaseTemp( value );

							emitter.MarkLabel( done );
						}
						else
						{
							emitter.Call( getHashCode );
						}
					}

					if ( i > 0 )
						emitter.Xor();
				}

				emitter.Return();

				typeBuilder.DefineMethodOverride(
						emitter.Method,
						typeof( IEqualityComparer<object> ).GetMethod(
							"GetHashCode",
							new Type[]
							{
								typeof( object )
							}
						)
					);
			}
			#endregion
			#endregion

			Type comparerType = typeBuilder.CreateType();

			return (IComparer) Activator.CreateInstance( comparerType );
		}