1
|
/*
|
2
|
Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
|
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
of this software and associated documentation files (the "Software"), to deal
|
5
|
in the Software without restriction, including without limitation the rights
|
6
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
copies of the Software, and to permit persons to whom the Software is
|
8
|
furnished to do so, subject to the following conditions:
|
9
|
|
10
|
The above copyright notice and this permission notice shall be included in
|
11
|
all copies or substantial portions of the Software.
|
12
|
|
13
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
SOFTWARE.
|
20
|
*/
|
21
|
|
22
|
using C5;
|
23
|
using System;
|
24
|
using System.Reflection;
|
25
|
using System.Reflection.Emit;
|
26
|
using System.Diagnostics;
|
27
|
using SCG = System.Collections.Generic;
|
28
|
|
29
|
namespace C5
|
30
|
{
|
31
|
/// <summary>
|
32
|
/// Utility class for building default generic equalityComparers.
|
33
|
/// </summary>
|
34
|
/// <typeparam name="T"></typeparam>
|
35
|
public static class EqualityComparer<T>
|
36
|
{
|
37
|
readonly static Type isequenced = typeof(ISequenced<>);
|
38
|
|
39
|
readonly static Type icollection = typeof(ICollection<>);
|
40
|
|
41
|
readonly static Type orderedcollectionequalityComparer = typeof(SequencedCollectionEqualityComparer<,>);
|
42
|
|
43
|
readonly static Type unorderedcollectionequalityComparer = typeof(UnsequencedCollectionEqualityComparer<,>);
|
44
|
|
45
|
readonly static Type equalityequalityComparer = typeof(EquatableEqualityComparer<>);
|
46
|
|
47
|
readonly static Type iequalitytype = typeof(IEquatable<T>);
|
48
|
|
49
|
static SCG.IEqualityComparer<T> cachedDefault = null;
|
50
|
|
51
|
//TODO: find the right word for initialized+invocation
|
52
|
/// <summary>
|
53
|
/// A default generic equality comparer for type T. The procedure is as follows:
|
54
|
/// <list>
|
55
|
/// <item>If T is a primitive type (char, sbyte, byte, short, ushort, int, uint, float, double, decimal),
|
56
|
/// the equalityComparer will be a standard equalityComparer for that type</item>
|
57
|
/// <item>If the actual generic argument T implements the generic interface
|
58
|
/// <see cref="T:C5.ISequenced`1"/> for some value W of its generic parameter T,
|
59
|
/// the equalityComparer will be <see cref="T:C5.SequencedCollectionEqualityComparer`2"/></item>
|
60
|
/// <item>If the actual generic argument T implements
|
61
|
/// <see cref="T:C5.ICollection`1"/> for some value W of its generic parameter T,
|
62
|
/// the equalityComparer will be <see cref="T:C5.UnsequencedCollectionEqualityComparer`2"/></item>
|
63
|
/// <item>If T is a type implementing <see cref="T:C5.IEquatable`1"/>, the equalityComparer
|
64
|
/// will be <see cref="T:C5.EquatableEqualityComparer`1"/></item>
|
65
|
/// <item>If T is a type not implementing <see cref="T:C5.IEquatable`1"/>, the equalityComparer
|
66
|
/// will be <see cref="T:C5.NaturalEqualityComparer`1"/> </item>
|
67
|
/// </list>
|
68
|
/// The <see cref="T:C5.IEqualityComparer`1"/> object is constructed when this class is initialised, i.e.
|
69
|
/// its static constructors called. Thus, the property will be the same object
|
70
|
/// for the duration of an invocation of the runtime, but a value serialized in
|
71
|
/// another invocation and deserialized here will not be the same object.
|
72
|
/// </summary>
|
73
|
/// <value></value>
|
74
|
public static SCG.IEqualityComparer<T> Default
|
75
|
{
|
76
|
get
|
77
|
{
|
78
|
if (cachedDefault != null)
|
79
|
return cachedDefault;
|
80
|
|
81
|
Type t = typeof(T);
|
82
|
|
83
|
if (t.IsValueType)
|
84
|
{
|
85
|
if (t.Equals(typeof(char)))
|
86
|
return cachedDefault = (SCG.IEqualityComparer<T>)(CharEqualityComparer.Default);
|
87
|
|
88
|
if (t.Equals(typeof(sbyte)))
|
89
|
return cachedDefault = (SCG.IEqualityComparer<T>)(SByteEqualityComparer.Default);
|
90
|
|
91
|
if (t.Equals(typeof(byte)))
|
92
|
return cachedDefault = (SCG.IEqualityComparer<T>)(ByteEqualityComparer.Default);
|
93
|
|
94
|
if (t.Equals(typeof(short)))
|
95
|
return cachedDefault = (SCG.IEqualityComparer<T>)(ShortEqualityComparer.Default);
|
96
|
|
97
|
if (t.Equals(typeof(ushort)))
|
98
|
return cachedDefault = (SCG.IEqualityComparer<T>)(UShortEqualityComparer.Default);
|
99
|
|
100
|
if (t.Equals(typeof(int)))
|
101
|
return cachedDefault = (SCG.IEqualityComparer<T>)(IntEqualityComparer.Default);
|
102
|
|
103
|
if (t.Equals(typeof(uint)))
|
104
|
return cachedDefault = (SCG.IEqualityComparer<T>)(UIntEqualityComparer.Default);
|
105
|
|
106
|
if (t.Equals(typeof(long)))
|
107
|
return cachedDefault = (SCG.IEqualityComparer<T>)(LongEqualityComparer.Default);
|
108
|
|
109
|
if (t.Equals(typeof(ulong)))
|
110
|
return cachedDefault = (SCG.IEqualityComparer<T>)(ULongEqualityComparer.Default);
|
111
|
|
112
|
if (t.Equals(typeof(float)))
|
113
|
return cachedDefault = (SCG.IEqualityComparer<T>)(FloatEqualityComparer.Default);
|
114
|
|
115
|
if (t.Equals(typeof(double)))
|
116
|
return cachedDefault = (SCG.IEqualityComparer<T>)(DoubleEqualityComparer.Default);
|
117
|
|
118
|
if (t.Equals(typeof(decimal)))
|
119
|
return cachedDefault = (SCG.IEqualityComparer<T>)(DecimalEqualityComparer.Default);
|
120
|
}
|
121
|
Type[] interfaces = t.GetInterfaces();
|
122
|
if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(isequenced))
|
123
|
return createAndCache(orderedcollectionequalityComparer.MakeGenericType(new Type[] { t, t.GetGenericArguments()[0] }));
|
124
|
foreach (Type ty in interfaces)
|
125
|
{
|
126
|
if (ty.IsGenericType && ty.GetGenericTypeDefinition().Equals(isequenced))
|
127
|
return createAndCache(orderedcollectionequalityComparer.MakeGenericType(new Type[] { t, ty.GetGenericArguments()[0] }));
|
128
|
}
|
129
|
if (t.IsGenericType && t.GetGenericTypeDefinition().Equals(icollection))
|
130
|
return createAndCache(unorderedcollectionequalityComparer.MakeGenericType(new Type[] { t, t.GetGenericArguments()[0] }));
|
131
|
foreach (Type ty in interfaces)
|
132
|
{
|
133
|
if (ty.IsGenericType && ty.GetGenericTypeDefinition().Equals(icollection))
|
134
|
return createAndCache(unorderedcollectionequalityComparer.MakeGenericType(new Type[] { t, ty.GetGenericArguments()[0] }));
|
135
|
}
|
136
|
if (iequalitytype.IsAssignableFrom(t))
|
137
|
return createAndCache(equalityequalityComparer.MakeGenericType(new Type[] { t }));
|
138
|
else
|
139
|
return cachedDefault = NaturalEqualityComparer<T>.Default;
|
140
|
}
|
141
|
}
|
142
|
static SCG.IEqualityComparer<T> createAndCache(Type equalityComparertype)
|
143
|
{
|
144
|
return cachedDefault = (SCG.IEqualityComparer<T>)(equalityComparertype.GetProperty("Default", BindingFlags.Static | BindingFlags.Public).GetValue(null, null));
|
145
|
}
|
146
|
}
|
147
|
|
148
|
/// <summary>
|
149
|
/// A default item equalityComparer calling through to
|
150
|
/// the GetHashCode and Equals methods inherited from System.Object.
|
151
|
/// </summary>
|
152
|
[Serializable]
|
153
|
public sealed class NaturalEqualityComparer<T> : SCG.IEqualityComparer<T>
|
154
|
{
|
155
|
static NaturalEqualityComparer<T> cached;
|
156
|
NaturalEqualityComparer() { }
|
157
|
/// <summary>
|
158
|
///
|
159
|
/// </summary>
|
160
|
/// <value></value>
|
161
|
public static NaturalEqualityComparer<T> Default { get { return cached ?? (cached = new NaturalEqualityComparer<T>()); } }
|
162
|
//TODO: check if null check is reasonable
|
163
|
//Answer: if we have struct C<T> { T t; int i;} and implement GetHashCode as
|
164
|
//the sum of hashcodes, and T may be any type, we cannot make the null check
|
165
|
//inside the definition of C<T> in a reasonable way.
|
166
|
/// <summary>
|
167
|
/// Get the hash code with respect to this item equalityComparer
|
168
|
/// </summary>
|
169
|
/// <param name="item">The item</param>
|
170
|
/// <returns>The hash code</returns>
|
171
|
[Tested]
|
172
|
public int GetHashCode(T item) { return item == null ? 0 : item.GetHashCode(); }
|
173
|
|
174
|
/// <summary>
|
175
|
/// Check if two items are equal with respect to this item equalityComparer
|
176
|
/// </summary>
|
177
|
/// <param name="item1">first item</param>
|
178
|
/// <param name="item2">second item</param>
|
179
|
/// <returns>True if equal</returns>
|
180
|
[Tested]
|
181
|
public bool Equals(T item1, T item2)
|
182
|
{
|
183
|
return item1 == null ? item2 == null : item1.Equals(item2);
|
184
|
}
|
185
|
}
|
186
|
|
187
|
/// <summary>
|
188
|
/// A default equality comparer for a type T that implements System.IEquatable<typeparamref name="T"/>.
|
189
|
///
|
190
|
/// The equality comparer forwards calls to GetHashCode and Equals to the IEquatable methods
|
191
|
/// on T, so Equals(T) is called, not Equals(object).
|
192
|
/// This will save boxing abd unboxing if T is a value type
|
193
|
/// and in general saves a runtime type check.
|
194
|
/// </summary>
|
195
|
/// <typeparam name="T"></typeparam>
|
196
|
[Serializable]
|
197
|
public class EquatableEqualityComparer<T> : SCG.IEqualityComparer<T> where T : IEquatable<T>
|
198
|
{
|
199
|
static EquatableEqualityComparer<T> cached = new EquatableEqualityComparer<T>();
|
200
|
EquatableEqualityComparer() { }
|
201
|
/// <summary>
|
202
|
///
|
203
|
/// </summary>
|
204
|
/// <value></value>
|
205
|
public static EquatableEqualityComparer<T> Default {
|
206
|
get { return cached ?? (cached = new EquatableEqualityComparer<T>()); }
|
207
|
}
|
208
|
/// <summary>
|
209
|
///
|
210
|
/// </summary>
|
211
|
/// <param name="item"></param>
|
212
|
/// <returns></returns>
|
213
|
public int GetHashCode(T item) { return item == null ? 0 : item.GetHashCode(); }
|
214
|
|
215
|
/// <summary>
|
216
|
///
|
217
|
/// </summary>
|
218
|
/// <param name="item1"></param>
|
219
|
/// <param name="item2"></param>
|
220
|
/// <returns></returns>
|
221
|
public bool Equals(T item1, T item2) { return item1 == null ? item2 == null : item1.Equals(item2); }
|
222
|
}
|
223
|
|
224
|
/// <summary>
|
225
|
/// A equalityComparer for a reference type that uses reference equality for equality and the hash code from object as hash code.
|
226
|
/// </summary>
|
227
|
/// <typeparam name="T">The item type. Must be a reference type.</typeparam>
|
228
|
[Serializable]
|
229
|
public class ReferenceEqualityComparer<T> : SCG.IEqualityComparer<T> where T : class
|
230
|
{
|
231
|
static ReferenceEqualityComparer<T> cached;
|
232
|
ReferenceEqualityComparer() { }
|
233
|
/// <summary>
|
234
|
///
|
235
|
/// </summary>
|
236
|
/// <value></value>
|
237
|
public static ReferenceEqualityComparer<T> Default {
|
238
|
get { return cached ?? (cached = new ReferenceEqualityComparer<T>()); }
|
239
|
}
|
240
|
/// <summary>
|
241
|
///
|
242
|
/// </summary>
|
243
|
/// <param name="item"></param>
|
244
|
/// <returns></returns>
|
245
|
public int GetHashCode(T item)
|
246
|
{
|
247
|
return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(item);
|
248
|
}
|
249
|
|
250
|
/// <summary>
|
251
|
///
|
252
|
/// </summary>
|
253
|
/// <param name="i1"></param>
|
254
|
/// <param name="i2"></param>
|
255
|
/// <returns></returns>
|
256
|
public bool Equals(T i1, T i2)
|
257
|
{
|
258
|
return object.ReferenceEquals(i1, i2);
|
259
|
}
|
260
|
}
|
261
|
|
262
|
/// <summary>
|
263
|
/// An equalityComparer compatible with a given comparer. All hash codes are 0,
|
264
|
/// meaning that anything based on hash codes will be quite inefficient.
|
265
|
/// <para><b>Note: this will give a new EqualityComparer each time created!</b></para>
|
266
|
/// </summary>
|
267
|
/// <typeparam name="T"></typeparam>
|
268
|
[Serializable]
|
269
|
public class ComparerZeroHashCodeEqualityComparer<T> : SCG.IEqualityComparer<T>
|
270
|
{
|
271
|
SCG.IComparer<T> comparer;
|
272
|
/// <summary>
|
273
|
/// Create a trivial <see cref="T:C5.IEqualityComparer`1"/> compatible with the
|
274
|
/// <see cref="T:C5.IComparer`1"/> <code>comparer</code>
|
275
|
/// </summary>
|
276
|
/// <param name="comparer"></param>
|
277
|
public ComparerZeroHashCodeEqualityComparer(SCG.IComparer<T> comparer)
|
278
|
{
|
279
|
if (comparer == null)
|
280
|
throw new NullReferenceException("Comparer cannot be null");
|
281
|
this.comparer = comparer;
|
282
|
}
|
283
|
/// <summary>
|
284
|
/// A trivial, inefficient hash fuction. Compatible with any equality relation.
|
285
|
/// </summary>
|
286
|
/// <param name="item"></param>
|
287
|
/// <returns>0</returns>
|
288
|
public int GetHashCode(T item) { return 0; }
|
289
|
/// <summary>
|
290
|
/// Equality of two items as defined by the comparer.
|
291
|
/// </summary>
|
292
|
/// <param name="item1"></param>
|
293
|
/// <param name="item2"></param>
|
294
|
/// <returns></returns>
|
295
|
public bool Equals(T item1, T item2) { return comparer.Compare(item1, item2) == 0; }
|
296
|
}
|
297
|
|
298
|
/// <summary>
|
299
|
/// Prototype for a sequenced equalityComparer for something (T) that implements ISequenced[W].
|
300
|
/// This will use ISequenced[W] specific implementations of the equality comparer operations.
|
301
|
/// </summary>
|
302
|
/// <typeparam name="T"></typeparam>
|
303
|
/// <typeparam name="W"></typeparam>
|
304
|
[Serializable]
|
305
|
public class SequencedCollectionEqualityComparer<T, W> : SCG.IEqualityComparer<T>
|
306
|
where T : ISequenced<W>
|
307
|
{
|
308
|
static SequencedCollectionEqualityComparer<T, W> cached;
|
309
|
SequencedCollectionEqualityComparer() { }
|
310
|
/// <summary>
|
311
|
///
|
312
|
/// </summary>
|
313
|
/// <value></value>
|
314
|
public static SequencedCollectionEqualityComparer<T, W> Default {
|
315
|
get { return cached ?? (cached = new SequencedCollectionEqualityComparer<T, W>()); }
|
316
|
}
|
317
|
/// <summary>
|
318
|
/// Get the hash code with respect to this sequenced equalityComparer
|
319
|
/// </summary>
|
320
|
/// <param name="collection">The collection</param>
|
321
|
/// <returns>The hash code</returns>
|
322
|
[Tested]
|
323
|
public int GetHashCode(T collection) { return collection.GetSequencedHashCode(); }
|
324
|
|
325
|
/// <summary>
|
326
|
/// Check if two items are equal with respect to this sequenced equalityComparer
|
327
|
/// </summary>
|
328
|
/// <param name="collection1">first collection</param>
|
329
|
/// <param name="collection2">second collection</param>
|
330
|
/// <returns>True if equal</returns>
|
331
|
[Tested]
|
332
|
public bool Equals(T collection1, T collection2) { return collection1 == null ? collection2 == null : collection1.SequencedEquals(collection2); }
|
333
|
}
|
334
|
|
335
|
/// <summary>
|
336
|
/// Prototype for an unsequenced equalityComparer for something (T) that implements ICollection[W]
|
337
|
/// This will use ICollection[W] specific implementations of the equalityComparer operations
|
338
|
/// </summary>
|
339
|
/// <typeparam name="T"></typeparam>
|
340
|
/// <typeparam name="W"></typeparam>
|
341
|
[Serializable]
|
342
|
public class UnsequencedCollectionEqualityComparer<T, W> : SCG.IEqualityComparer<T>
|
343
|
where T : ICollection<W>
|
344
|
{
|
345
|
static UnsequencedCollectionEqualityComparer<T, W> cached;
|
346
|
UnsequencedCollectionEqualityComparer() { }
|
347
|
/// <summary>
|
348
|
///
|
349
|
/// </summary>
|
350
|
/// <value></value>
|
351
|
public static UnsequencedCollectionEqualityComparer<T, W> Default { get { return cached ?? (cached = new UnsequencedCollectionEqualityComparer<T, W>()); } }
|
352
|
/// <summary>
|
353
|
/// Get the hash code with respect to this unsequenced equalityComparer
|
354
|
/// </summary>
|
355
|
/// <param name="collection">The collection</param>
|
356
|
/// <returns>The hash code</returns>
|
357
|
[Tested]
|
358
|
public int GetHashCode(T collection) { return collection.GetUnsequencedHashCode(); }
|
359
|
|
360
|
|
361
|
/// <summary>
|
362
|
/// Check if two collections are equal with respect to this unsequenced equalityComparer
|
363
|
/// </summary>
|
364
|
/// <param name="collection1">first collection</param>
|
365
|
/// <param name="collection2">second collection</param>
|
366
|
/// <returns>True if equal</returns>
|
367
|
[Tested]
|
368
|
public bool Equals(T collection1, T collection2) { return collection1 == null ? collection2 == null : collection1.UnsequencedEquals(collection2); }
|
369
|
}
|
370
|
|
371
|
}
|
372
|
|
373
|
|
374
|
#if EXPERIMENTAL
|
375
|
namespace C5.EqualityComparerBuilder
|
376
|
{
|
377
|
|
378
|
/// <summary>
|
379
|
/// IEqualityComparer factory class: examines at instatiation time if T is an
|
380
|
/// interface implementing "int GetHashCode()" and "bool Equals(T)".
|
381
|
/// If those are not present, MakeEqualityComparer will return a default equalityComparer,
|
382
|
/// else this class will implement IequalityComparer[T] via Invoke() on the
|
383
|
/// reflected method infos.
|
384
|
/// </summary>
|
385
|
public class ByInvoke<T> : SCG.IEqualityComparer<T>
|
386
|
{
|
387
|
internal static readonly System.Reflection.MethodInfo hinfo, einfo;
|
388
|
|
389
|
|
390
|
static ByInvoke()
|
391
|
{
|
392
|
Type t = typeof(T);
|
393
|
|
394
|
if (!t.IsInterface) return;
|
395
|
|
396
|
BindingFlags f = BindingFlags.Public | BindingFlags.Instance;
|
397
|
|
398
|
hinfo = t.GetMethod("GetHashCode", f, null, new Type[0], null);
|
399
|
einfo = t.GetMethod("Equals", f, null, new Type[1] { t }, null);
|
400
|
}
|
401
|
|
402
|
|
403
|
private ByInvoke() { }
|
404
|
|
405
|
/// <summary>
|
406
|
///
|
407
|
/// </summary>
|
408
|
/// <returns></returns>
|
409
|
public static SCG.IEqualityComparer<T> MakeEqualityComparer()
|
410
|
{
|
411
|
if (hinfo != null && einfo != null)
|
412
|
return new ByInvoke<T>();
|
413
|
else
|
414
|
return NaturalEqualityComparer<T>.Default;
|
415
|
}
|
416
|
|
417
|
/// <summary>
|
418
|
///
|
419
|
/// </summary>
|
420
|
/// <param name="item"></param>
|
421
|
/// <returns></returns>
|
422
|
public int GetHashCode(T item)
|
423
|
{
|
424
|
return (int)(hinfo.Invoke(item, null));
|
425
|
}
|
426
|
|
427
|
/// <summary>
|
428
|
///
|
429
|
/// </summary>
|
430
|
/// <param name="i1"></param>
|
431
|
/// <param name="i2"></param>
|
432
|
/// <returns></returns>
|
433
|
public bool Equals(T i1, T i2)
|
434
|
{
|
435
|
return (bool)(einfo.Invoke(i1, new object[1] { i2 }));
|
436
|
}
|
437
|
}
|
438
|
|
439
|
|
440
|
|
441
|
/// <summary>
|
442
|
/// Like ByInvoke, but tries to build a equalityComparer by RTCG to
|
443
|
/// avoid the Invoke() overhead.
|
444
|
/// </summary>
|
445
|
public class ByRTCG
|
446
|
{
|
447
|
private static ModuleBuilder moduleBuilder;
|
448
|
|
449
|
private static AssemblyBuilder assemblyBuilder;
|
450
|
|
451
|
/// <summary>
|
452
|
///
|
453
|
/// </summary>
|
454
|
/// <param name="hinfo"></param>
|
455
|
/// <param name="einfo"></param>
|
456
|
/// <returns></returns>
|
457
|
public static SCG.IEqualityComparer<T> CreateEqualityComparer<T>(MethodInfo hinfo, MethodInfo einfo)
|
458
|
{
|
459
|
if (moduleBuilder == null)
|
460
|
{
|
461
|
string assmname = "LeFake";
|
462
|
string filename = assmname + ".dll";
|
463
|
AssemblyName assemblyName = new AssemblyName("LeFake");
|
464
|
AppDomain appdomain = AppDomain.CurrentDomain;
|
465
|
AssemblyBuilderAccess acc = AssemblyBuilderAccess.RunAndSave;
|
466
|
|
467
|
assemblyBuilder = appdomain.DefineDynamicAssembly(assemblyName, acc);
|
468
|
moduleBuilder = assemblyBuilder.DefineDynamicModule(assmname, filename);
|
469
|
}
|
470
|
|
471
|
Type t = typeof(T);
|
472
|
Type o_t = typeof(object);
|
473
|
Type h_t = typeof(SCG.IEqualityComparer<T>);
|
474
|
Type i_t = typeof(int);
|
475
|
//TODO: protect uid for thread safety!
|
476
|
string name = "C5.Dynamic.EqualityComparer_" + Guid.NewGuid().ToString();
|
477
|
TypeAttributes tatt = TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed;
|
478
|
TypeBuilder tb = moduleBuilder.DefineType(name, tatt, o_t, new Type[1] { h_t });
|
479
|
MethodAttributes matt = MethodAttributes.Public | MethodAttributes.Virtual;
|
480
|
MethodBuilder mb = tb.DefineMethod("GetHashCode", matt, i_t, new Type[1] { t });
|
481
|
ILGenerator ilg = mb.GetILGenerator();
|
482
|
|
483
|
ilg.Emit(OpCodes.Ldarg_1);
|
484
|
ilg.Emit(OpCodes.Callvirt, hinfo);
|
485
|
ilg.Emit(OpCodes.Ret);
|
486
|
mb = tb.DefineMethod("Equals", matt, typeof(bool), new Type[2] { t, t });
|
487
|
ilg = mb.GetILGenerator();
|
488
|
ilg.Emit(OpCodes.Ldarg_1);
|
489
|
ilg.Emit(OpCodes.Ldarg_2);
|
490
|
ilg.Emit(OpCodes.Callvirt, einfo);
|
491
|
ilg.Emit(OpCodes.Ret);
|
492
|
|
493
|
Type equalityComparer_t = tb.CreateType();
|
494
|
object equalityComparer = equalityComparer_t.GetConstructor(new Type[0]).Invoke(null);
|
495
|
|
496
|
return (SCG.IEqualityComparer<T>)equalityComparer;
|
497
|
}
|
498
|
|
499
|
/// <summary>
|
500
|
///
|
501
|
/// </summary>
|
502
|
/// <typeparam name="T"></typeparam>
|
503
|
/// <returns></returns>
|
504
|
public static SCG.IEqualityComparer<T> build<T>()
|
505
|
{
|
506
|
MethodInfo hinfo = ByInvoke<T>.hinfo, einfo = ByInvoke<T>.einfo;
|
507
|
|
508
|
if (hinfo != null && einfo != null)
|
509
|
return CreateEqualityComparer<T>(hinfo, einfo);
|
510
|
else
|
511
|
return EqualityComparer<T>.Default;
|
512
|
}
|
513
|
|
514
|
/// <summary>
|
515
|
///
|
516
|
/// </summary>
|
517
|
public void dump()
|
518
|
{
|
519
|
assemblyBuilder.Save("LeFake.dll");
|
520
|
}
|
521
|
}
|
522
|
}
|
523
|
#endif
|