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 ); }
public override void Compile( MethodEmitter emitter ) { emitter.Chain( m_Property ); bool inverse = false; bool couldCompare = emitter.CompareTo( 1, delegate() { m_Value.Load( emitter ); } ); if ( couldCompare ) { emitter.Load( 0 ); switch ( m_Operator ) { case ComparisonOperator.Equal: emitter.Compare( OpCodes.Ceq ); break; case ComparisonOperator.NotEqual: emitter.Compare( OpCodes.Ceq ); inverse = true; break; case ComparisonOperator.Greater: emitter.Compare( OpCodes.Cgt ); break; case ComparisonOperator.GreaterEqual: emitter.Compare( OpCodes.Clt ); inverse = true; break; case ComparisonOperator.Lesser: emitter.Compare( OpCodes.Clt ); break; case ComparisonOperator.LesserEqual: emitter.Compare( OpCodes.Cgt ); inverse = true; break; default: throw new InvalidOperationException( "Invalid comparison operator." ); } } else { // This type is -not- comparable // We can only support == and != operations m_Value.Load( emitter ); switch ( m_Operator ) { case ComparisonOperator.Equal: emitter.Compare( OpCodes.Ceq ); break; case ComparisonOperator.NotEqual: emitter.Compare( OpCodes.Ceq ); inverse = true; break; case ComparisonOperator.Greater: case ComparisonOperator.GreaterEqual: case ComparisonOperator.Lesser: case ComparisonOperator.LesserEqual: throw new InvalidOperationException( "Property does not support relational comparisons." ); default: throw new InvalidOperationException( "Invalid operator." ); } } if ( m_Not != inverse ) emitter.LogicalNot(); }
public static IComparer Compile( AssemblyEmitter assembly, Type objectType, OrderInfo[] orders ) { TypeBuilder typeBuilder = assembly.DefineType( "__sort", 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 < orders.Length; ++i ) { if ( i > 0 ) { emitter.LoadLocal( v ); emitter.BranchIfTrue( end ); // if ( v != 0 ) return v; } OrderInfo orderInfo = orders[i]; Property prop = orderInfo.Property; int sign = orderInfo.Sign; emitter.LoadLocal( a ); emitter.Chain( prop ); bool couldCompare = emitter.CompareTo( sign, 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 Type comparerType = typeBuilder.CreateType(); return (IComparer) Activator.CreateInstance( comparerType ); }