|
|
|
|||||
|
C# code generated for comparison methods
A Slice struct can be mapped to a C# struct or class, depending on the Slice directive used. For the comparison methods and equality operators, slice2cs generates the same code for classes and structs. However, this code is not optimal for either case, since it tries to satisfy both.
As an example let's use this Slice declaration: Code:
struct A { string str; int num; };
and http://msdn.microsoft.com/library/de...lsoperator.asp the basic guidelines are these: * For value types, whenever you override Equals (instance method), you should also overload the equality operators, as value types do not have a default implementation for them. * For reference types, do not overload the equality operators, as there is a default implementation which uses the Equals() method. See http://msdn.microsoft.com/library/de...alitytopic.asp. * You rarely ever need to re-implement the *static* Equals method, as its default implementation uses the instance method. From http://msdn.microsoft.com/library/de...qualsTopic.asp it becomes clear that the implementation generated by slice2cs just duplicates the default. The generated code look like this, the comments are based on the guidelines above: Code:
public override bool Equals(object __other)
{
// for struct mapping,this will likely box "this", always returning false
if(object.ReferenceEquals(this, __other))
{
return true;
}
// This will evaluate to true for any two subclasses of A;
// this may be OK if is it desired that two different instances
// are equal even if only their A portion is equal and they
// don't override Equals(). Seems unusual.
if(!(__other is A))
{
return false;
}
// If we want to avoid multiple "(A)__other" casts below, we could
// use A other = (A)__other, but for structs this may be inefficient
// as it leads to a struct copy, whereas otherwise the compiler
// may optimize away the struct instantiation.
// Why not use string.Equals(this.str, ((A)__other).str)?
if(str == null)
{
if(((A)__other).str != null)
{
return false;
}
}
else
{
if(!(str.Equals(((A)__other).str)))
{
return false;
}
}
if(!(num.Equals(((A)__other).num)))
{
return false;
}
return true;
}
// redundant - as per guidelines
public static bool Equals(A __lhs, A __rhs)
{
return object.ReferenceEquals(__lhs, null)
? object.ReferenceEquals(__rhs, null)
: __lhs.Equals(__rhs);
}
// overloading equality operators is recommended for value types,
// but not for reference types, so we should have two kinds of code
public static bool operator==(A __lhs, A __rhs)
{
return Equals(__lhs, __rhs);
}
public static bool operator!=(A __lhs, A __rhs)
{
return !Equals(__lhs, __rhs);
}
For struct mapping: =================== Here is how it could be done specifically for C# structs: (simpler because structs cannot be null or derived from) Code:
public override bool Equals(object __other)
{
// we can use 'is' because there are no structs derived from A
return __other is A && this == (A)__other;
}
// no null checks necessary - we have structs as arguments
public static bool operator==(A __lhs, A __rhs)
{
return string.Equals(__lhs.str, __rhs.str) && __lhs.num.Equals(__rhs.num);
}
public static bool operator!=(A __lhs, A __rhs)
{
return !(__lhs == __rhs);
}
For class mapping: ================== No static Equals() implementation, no operator overloads. This would be a simpler approach, as it also avoids repeated casts. Code:
public override bool Equals(object __other)
{
// we could use "if (!(__other is A))" depending on the
// desired semantics - the ususal (MSDN) way is shown below.
if (__other == null || GetType() != __other.GetType())
return false;
// avoid multiple casts, no value type copying here
A other = (A)__other;
// note we are not using ==, since value types do not have a default implementation for ==
return string.Equals(this.str, other.str) && num.Equals(other.num);
}
|
|
|||||||
|
Quote:
Quote:
Quote:
Quote:
Quote:
Quote:
For C#, I guess the situation is different because the formal parameter type of the non-static Equals is System.Object. On the whole, I agree with you; it is probably overall safer to generate Equals as you suggested, making sure that the types of both operands match. Quote:
Cheers, Michi. |
|
|||||
|
Quote:
However, there is nothing better than trying it out yourself, and the result is that you are right. The default reference type implementation of equality operators apparently does not call the static Equals() method, only ReferenceEquals(). I have to go back now and check some of my code. :-( However, now that you have to overload the equality operators anyway, I suggest doing it like it is done for structs, that is, put the actual comparison code into the equality operator implementation, not into Equals(). The reason is that Equals() is a virtual method and cannot (currently) be inlined. So I suggest something like this (similar to the code for structs): Code:
public override bool Equals(object __other)
{
if (__other == null || GetType() != __other.GetType())
return false;
return this == (A)__other;
}
public static bool operator==(A __lhs, A __rhs)
{
if (object.ReferenceEquals(__lhs, __rhs))
return true;
if (object.ReferenceEquals(__lhs, null) || object.ReferenceEquals(__rhs, null))
return false;
// return __lhs.str == __rhs.str && __lhs.num == __rhs.num;
return string.Equals(__lhs.str, __rhs.str) && int.Equals(__lhs.num, __rhs.num);
}
public static bool operator!=(A __lhs, A __rhs)
{
return !(__lhs == __rhs);
}
Quote:
I did it that way for the general case, since value types do not have a default implementation for the equality operators. For our specific example - strings and ints - I would probably just use this code: Code:
return __lhs.str == __rhs.str && __lhs.num == __rhs.num; Karl |
![]() |
| Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
| Thread Tools | |
| Display Modes | Rate This Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| Generated C# code indentation | kwaclaw | Comments | 1 | 11-24-2006 12:58 PM |
| How do YOU handle redundant generated slice code? | ctennis | Help Center | 1 | 11-10-2006 04:02 PM |
| Java/C#/C++ latency comparison | johnstv3 | Help Center | 3 | 09-13-2005 08:10 PM |
| assert() in slice2java generated code? | SteveWampler | Help Center | 2 | 04-13-2004 02:38 PM |
| Compiling slice2cpp-generated-code on Win. XP Pro | catalin | Help Center | 21 | 10-29-2003 10:56 PM |