locked
C#: Declaring structs with override methods? RRS feed

  • Question

  •  

    Why can you declare a method in structs using the 'override' keyword?

     

    This is weird to me, because a struct is sealed and cannot inherit. Why then are you allowed to 'override'?


    Example of struct with a method declared using 'override'. Code was found online at another website.

     

    Code Snippet

     

    struct Direct
    {
        public Direct(int value)
        {
            field = value;
        }

     

        public override bool Equals(object other) // <===== override keyword here?
        {
            return other is Direct && Equals((Direct)other);
        }
       
        public static bool operator==(Direct lhs, Direct rhs)
        {
            return lhs.Equals(rhs);
        }
       
        //...   

        private bool Equals(Direct other)
        {
            return field == other.field;
        }
       
        private int field;
    }

     

     

    Saturday, March 29, 2008 4:22 AM

Answers

  • Although you can use the override keyword in structs, you cannot use the virtual keyword, because a struct cannot be inherited from, although the struct itself inherits from System.ValueType.

     

    Every value type (including all structs) inherit from "System.ValueType", which itself inherits from "System.Object", which contains some default methods, such as Equals, GetHashCode, GetType and ToString. 

     

    System.Object contains methods that will check for equality.  System.ValueType actually overrides System.Object's version of the Object.Equals(object other) method, and implements a method that uses reflection to check equality based on the properties in the structure.  The System.ValueType implementation of equality is what is used by default in all structs.  This implementation, because it uses reflection, is pretty slow, which leads to why this developer overrides the Equals method.

     

    In the situation above, equality is judged solely on the basis of whether or not the field "field" in both instances of the structure are equal.  Explicitly declaring the equality between the type, by comparing integers is much faster than gathering metadata for a type, and rolling through all the properties. 

     

    Although value types are sealed and cannot be derived from, System.ValueType itself is not sealed.  Thus, you can override these methods in a struct exactly once. 

     

     

    Saturday, March 29, 2008 5:06 AM

All replies

  •  

    Structs are dervied from the ValueType class which in turn is dervied from the Object class where in the Equals method is declared virtual ( see http://msdn2.microsoft.com/en-us/library/bsc2ak47.aspx)
    Saturday, March 29, 2008 5:04 AM
  • Although you can use the override keyword in structs, you cannot use the virtual keyword, because a struct cannot be inherited from, although the struct itself inherits from System.ValueType.

     

    Every value type (including all structs) inherit from "System.ValueType", which itself inherits from "System.Object", which contains some default methods, such as Equals, GetHashCode, GetType and ToString. 

     

    System.Object contains methods that will check for equality.  System.ValueType actually overrides System.Object's version of the Object.Equals(object other) method, and implements a method that uses reflection to check equality based on the properties in the structure.  The System.ValueType implementation of equality is what is used by default in all structs.  This implementation, because it uses reflection, is pretty slow, which leads to why this developer overrides the Equals method.

     

    In the situation above, equality is judged solely on the basis of whether or not the field "field" in both instances of the structure are equal.  Explicitly declaring the equality between the type, by comparing integers is much faster than gathering metadata for a type, and rolling through all the properties. 

     

    Although value types are sealed and cannot be derived from, System.ValueType itself is not sealed.  Thus, you can override these methods in a struct exactly once. 

     

     

    Saturday, March 29, 2008 5:06 AM
  • Typically you will want to override some methods on a valuetype to avoid boxing.

    Boxing is the process of creating an object representation of an value type, unboxing is the opposite.

    Boxing is a costly operation and needs to be avoided if you can and if performance is important to you.

    So if you create your own structs and use the toString method, then override it for your struct.

     

    Saturday, March 29, 2008 1:01 PM
  •  David M Morton wrote:

    Although you can use the override keyword in structs, you cannot use the virtual keyword, because a struct cannot be inherited from, although the struct itself inherits from System.ValueType.

     

    Every value type (including all structs) inherit from "System.ValueType", which itself inherits from "System.Object", which contains some default methods, such as Equals, GetHashCode, GetType and ToString. 

    ....

     

     

    That now makes more sense. structs inherits from System.ValueType and thus you can use the override keyword. A few more questions:

     

    1. I guess Classes can be blueprints both Structs and Objects?

     

    2. What is 'reflection'?

     

    3. I'm assuming that the System.ValueType.Equal(...) is faster than the System.Object.Equal(...)? According to you it is still slower and hence an impementation based on reflection. I made the assumpation that structs version of equal is faster than object's due to structs being introduced due to performance...

    Sunday, March 30, 2008 9:28 PM
  •  

    1. I'm not exactly sure what the question is here.  Yes, System.Object is a class, and it is the base of both value types an reference types (classes).

     

    2. Reflection is a term used to describe how the runtime can analyze the properties, fields, methods, etc of a particular type.  The process of analyzing a type, however, takes significant overhead.  Hopefully I'll explain this in the next section.

     

    3. System.ValueType.Equals is actually slower than System.Object.Equals, as System.Object.Equals only checks the hash code of the object which will return a unique value based on the identity of the object.  Object.Equals doesn't check the equality of the values within the item, but rather that the items are the same items.  Think of Object.Equals as being a check for whether a particular model of car is really the same instance of the car.  You might say Jane and Bob have the same car, because they both own Toyota Corollas, but Jane and Bob's car, although they're the same model, are still not the same car, as Jane has her Corolla, and Bob has his Corolla. 

     

    Try this code in your compiler:

     

    Code Snippet

    MyClass o1 = new MyClass();

    MyClass o2 = new MyClass();

    o1.MyValue = 1;

    o1.MyValue = 1;

    MessageBox.Show((o1.Equals(o2)).ToString());

     

     

    You'll notice the result is "False". Although the value of the object is the same, and both objects have the same value for MyValue (assume MyValue is the only property), the references to the objects are not the same, and that is what the .Equals method tests by default.  

     

    The System.ValueType implementation of Equals actually checks the value of the types.  If you were to change MyClass to a struct, and rename it to MyStruct, you would have similar code with a different result (the result would be 'True').

     

    Code Snippet

    MyStruct o1 = new MyStruct();

    MyStruct o2 = new MyStruct();

    o1.MyValue = 1;

    o1.MyValue = 1;

    MessageBox.Show((o1.Equals(o2)).ToString());

     

    The reason being, is that the runtime would go through all the properties, calling the .Equals method on every property, and would return the result.  So it might return something like "this.Property1.Equals(obj.Property1) && this.Property2.Equals(obj.Property2)" and so on.  This is how System.ValueType's implementation of .Equals works, but before it compares the property values for equality between structs, it has to find which properties the type "MyStruct" contains, which is what reflection does.  The process of discovering a type's properties is not speedy, and adds some overhead when executing.  Overriding the Equals method in the MyStruct object, as follows will prevent the runtime from having to find those properties on it's own (because it explicitly states which properties to compare), and thus saves processor cycles:

     

    Code Snippet

    public override bool Equals(object obj)

    {

    return (obj is MyStruct && this.MyValue == (obj as MyStruct).MyValue);

    }

     

    And this is why it's good to override Equals in a struct.
    Monday, March 31, 2008 4:50 AM
  •  

    Thank you to everyone that responded especially to David Morton for addressing my questions in detail. It makes sense now! Smile

    Thursday, April 3, 2008 10:05 PM