Thursday, April 28, 2011

Why I cannot derive from long?

Hi

My function returns some long value which contains two values in lower and higher 32 bits.

I thought the best ways to handle return value is to derive my custom type from long and provide type extenders like GetLowerValue(), GetHigherValue().

The problem is that .NET does not allow to derive from long

If you compile that

public class SubmitOrderResult : long
{
}

you get:

cannot derive from sealed type 'long'

Why is that designed so and how can overcome it?

Thanks

From stackoverflow
  • You can't derive from any of the .NET Value Types - they are all sealed by definition.

    Perhaps you could implement your GetLowerValue and GetHigherValue methods as extension methods?

    James : +1 extension methods are definetly the way to go in this instance.
    Captain Comic : Right. So I'll go for extension. What I dislike about extension is that I will extend a common long type which might not necessarily be "my" long and does not contain two values in it. Deriving a new type would be more type-safe.
    Konrad Rudolph : @James: I somehow doubt that … a distinct types seems much more appropriate.
    Matt Howells : Create a new type which wraps a long field. See Bojan Resnik's answer.
    James : @Captain Comic, It is easy enough to simply ignore the methods and only use them when required.
    Tor Haugen : Well, a downside of this approach is that the extension methods will show up in intellisense for every long, whether appropriate or not.
    James : @Tor, valid point however as I commented in one of the other posts, you would only ever use the methods where appropriate. I find (maybe not everyone) that there are a always methods on various types/classes that aren't always relevant to what I need to do, this doesn't mean I am going to go create a custom type just to narrow down my intellisense.
  • As already mentioned value types in .NET are sealed so there is no way you can derive from long. You should create extension methods as suggested.

    Example

    public static class LongExtensions
    {
        public static long GetLowerValue(this long value)
        {
            ...
        }
    
        public static long GetHigherValue(this long value)
        {
            ...
        }
    }
    
  • You can't overcome it.

    As long is a sealed type and therefore you can't inherit from them. See the MSDN

    Because structs are implicitly sealed, they cannot be inherited.

    For more information, see Inheritance (C# Programming Guide).

  • If I understand correctly, your function actually returns two values, and the fact that you pack them into a long is an implementation detail. In that case, hide this detail and create a class which contains the value and the required operations:

    public class SubmitOrderResult
    {
        private readonly long value_;
    
        public int OneValue
        { 
            get { return (int)(value_ >> 32); } 
        }
    
        public int TheOtherValue
        { 
            get { return (int)(value_ & 0xFFFFFFFF); } 
        }
    
        public SubmitOrderResult(long value)
        { value_ = value; }
    }
    
    Konrad Rudolph : Why use `long` for storage at all? I fail to see the advantage … unless for interop with P/Invoke (or similar scenarios where low-level access makes sense).
    Bojan Resnik : I completely agree, and I used `long` because it was OP's requirement. The point I am trying to make is that whether or not OP chooses to actually use `long` in his function is an implementation detail and clients do not need to know about that.
  • My function returns some long value which contains two values in lower and higher 32 bits.

    That sounds like a really, really dirty hack. It could be appropriate for close-to-metal languages (e.g. C) but not for a higher-level, object-oriented language.

    In OO languages, you extend the type system, not harass existing types to do your bidding. Thus, the solution should be to create a new type which carries your information.

    Tor Haugen : My guess is it's not actually 'his' function, because then he wouldn't have this problem. Perhaps it's an extern, or at least some class library out of his control.
  • What you can do is write a struct with implicit conversion operators. That will work exactly the way you want:

    public struct SubmitOrderResult
    {
        private long _result;
    
        public SubmitOrderResult(long result)
        {
            _result = result;
        }
    
        public long Result
        {
            get { return _result; }
            set { _result = value; }
        }
    
        public int GetHigherValue()
        {
            return (int)(_result >> 32);
        }
    
        public int GetLowerValue()
        {
            return (int)_result;
        }
    
        public static implicit operator SubmitOrderResult(long result)
        {
            return new SubmitOrderResult(result);
        }
    
        public static implicit operator long(SubmitOrderResult result)
        {
            return result._result;
        }
    }
    

    Then you can do:

    SubmitOrderResult result = someObject.TheMethod();
    Console.WriteLine(result.GetHigherValue());
    Console.WriteLine(result.GetLowerValue());
    

    ...just like you wanted.

0 comments:

Post a Comment