0

Can I write something like this in C#

class A<TBase> : TBase {}

Here's what I'm trying to do roughly:

public class Comparable<T, TBase> : TBase, IComparable<T>
{
   public abstract int CompareTo(T other);

   public static bool CompareTo(T x, T y) {
     return x != null ? x.CompareTo(y) : (y != null ? 1 : 0);
   }

   public static bool operator<(T x, T y) {
     return CompareTo(x, y) < 0;
   }

   public static bool operator<=(T x, T y) {
     return CompareTo(x, y) <= 0;
   }

   public static bool operator>(T x, T y) {
     return CompareTo(x, y) > 0;
   }

   public static bool operator>=(T x, T y) {
     return CompareTo(x, y) >= 0;
   }

   public static bool operator==(T x, T y) {
     return CompareTo(x, y) == 0;
   }

   public static bool operator!=(T x, T y) {
     return CompareTo(x, y) != 0;
   }
}

Response to comments, here's some examples of the duplicated code I'm trying to avoid:

class Height {
  // This needs to be a class not an int because we want to forbid 
  // silly things like multiplying heights
  private int _heightInMillimeters;

  // Lots of comparison operators here:
  // ... 
}

class Weight {
  // This needs to be a class not an int because we want to forbid 
  // silly things like multiplying weights by heights etc
  private double _weightInKilograms;

  // Lots of comparison operators here:
  // ... 
}

class SomeOtherClassThatIdLikeToCompare {
  // More boilerplate comparison operators here
}
Clinton
  • 22,361
  • 15
  • 67
  • 163
  • Have you looked at using an interface? – Ryan S May 15 '18 at 04:58
  • How do I avoid having to define all six comparison operators for every class which implements the interface? – Clinton May 15 '18 at 05:01
  • If you can post a bit more of code, it would be clearer what you are trying to do – Low Flying Pelican May 15 '18 at 05:07
  • @LowFlyingPelican cheers and done. See the edited question. – Clinton May 15 '18 at 05:19
  • @Clinton Smells like an XY problem. Can you describe what you are ultimately trying to do? You seem to want to reduce duplicate code. Can you show how the code will be duplicated if you didn't use a generic parameter as base class? – Sweeper May 15 '18 at 05:39
  • Looks like it's a compiler limitation / by design. See https://stackoverflow.com/questions/5890516/in-c-sharp-4-0-is-it-possible-to-derive-a-class-from-a-generic-type-parameter – Low Flying Pelican May 15 '18 at 05:41
  • This is a duplicate many times over. See https://stackoverflow.com/questions/5890516/in-c-sharp-4-0-is-it-possible-to-derive-a-class-from-a-generic-type-parameter/5890813#5890813 or https://stackoverflow.com/questions/1842636/why-cannot-c-sharp-generics-derive-from-one-of-the-generic-type-parameters-like/1842855#1842855 or https://stackoverflow.com/questions/1842636/why-cannot-c-sharp-generics-derive-from-one-of-the-generic-type-parameters-like/1843557#1843557 or https://stackoverflow.com/questions/1849107/what-are-the-good-reasons-to-wish-that-net-generics-could-inherit-one-of-the-ge – Eric Lippert May 15 '18 at 05:42
  • @Sweeper see the new edit, should describe where the code duplication is occuring – Clinton May 15 '18 at 05:45
  • To answer your question which you ask in the comment: you don't avoid it. You copy-paste those 12 lines of code, which takes about half a second. – Eric Lippert May 15 '18 at 05:45
  • Why are your height, weight, etc, unit types classes and not structs? Why is height in millimeters not a double? You can be 0.5 mm high. – Eric Lippert May 15 '18 at 05:46
  • @EricLippert you could also be 0.2mm high but one can't represent that as a double either. I'm not sure what you're getting at. – Clinton May 15 '18 at 05:48
  • @EricLippert: they could be structs but structs don't seem to have comparison operators automatically defined unless I've missed something – Clinton May 15 '18 at 05:49
  • @Clinton: That is exactly the point of using doubles for physical quantities: **the representation error in the double is many orders of magnitude smaller than the measurement error of the quantity**. You don't have a ruler precise enough to measure 0.2 mm within the tolerances of the error in a double. – Eric Lippert May 15 '18 at 05:49
  • They should be structs for efficiency reasons; you're using many, many times more memory than necessary to represent these quantities. A four byte struct is four bytes. A four byte class is four bytes, plus the sync block and the vtable, and you can only access the value via a dereference. Always use value types to represent immutable mathematical values! – Eric Lippert May 15 '18 at 05:51
  • @EricLippert it really depends on the particular business rules of the application you're developing. If you're storing measurements taken whole millimeters not fractions ints are appropriate. But I think you're missing the point of the question. – Clinton May 15 '18 at 05:52
  • Also you're creating collection pressure every time you make one of those classes, and you're likely to make lots of them. – Eric Lippert May 15 '18 at 05:52
  • Oh, the question was answered long ago. You can't do what you want. I'm taking this opportunity to help you find all the design flaws now, so that you don't have to find them later. – Eric Lippert May 15 '18 at 05:53
  • If this subject interests you, you might consider researching how F# represents units of measure; this type system was designed by the same person who designed the C# generic type system. – Eric Lippert May 15 '18 at 05:54
  • @EricLippert: Interestingly I've just worked out I can write generic extension methods `LessThan`, `GreaterThan` which take `where T : IComparable` arguments etc and achieve the effect I'm after, except that I can't use nicer looking operators. Seems like a simple syntactic limitation rather than a deep structural one. – Clinton May 15 '18 at 06:00
  • That's correct. Extension operators might make it into a future version of c#. – Eric Lippert May 15 '18 at 06:14
  • @EricLippert I guess that's the approach I'll use for the moment then – Clinton May 15 '18 at 06:14

0 Answers0