3

I need to create a class/classes in C# that will contain constants for paper sizes properties like dimensions, aspect ratio, horizontal and vertical resolution etc. for various paper sizes like A4, Letter and so on. The first idea was to create an interface(or abstract class) IPaperSize from which we would have inherited classes A4Paper, LetterPaper etc. with the values stored inside. It also makes sense to make the classes static since it only stores constants, but with the current design I am unable to make it static because of inheriting from interface. What's the best approach here?

  • What purpose the interface or abstract class? Don't create one if you don't use it outside of inheritance. If you use it, you can't use static classes either. – Frank Hileman May 4 '18 at 18:43
  • Terminology: one inherits from a class, but implements an interface. – radarbob May 7 '18 at 20:39
  • just use an enum and export an "encode" that maps string names to constants, and "decode" that maps constants to strings. this way your class instances can be used to encode/decode constants in a binary compatible language agonistic way that works everywhere from jscript to assembly. use ifs for small encode/decodes, hash tables for large ones. – Dmitry May 8 '18 at 4:55
  • @radarbob Changed, my bad. – Nemanja Petrović May 8 '18 at 12:27
10

I need to create a class/classes in C#...

No, you need to create a set of fixed values. Don't instantly therefore think of classes. Leave that decision until later.

So, you need a collection of values, grouped by paper type. The structure that comes to mind therefore is a dictionary. The paper size is the key, the aspects of that size are the value.

Now at this point, we need to make a decision. You talk about many properties of each paper size. But in reality, only two are needed: the width and height. From that, the aspect ratio etc can all be calculated. So do you manually calculate them once and and define multiple properties, or just set the width and height and calculate the other values at runtime? Let's go with calculating them just once at runtime, at startup.

So with that, we now know we need a class (or struct, if you prefer, since we are using C# here. But I'll stick with a class):

public sealed class PaperDetails
{
    public PaperDetails(double width, double height)
    {
        Width = width;
        Height = height;
        AspectRatio = width/height;
        ...
    }

    public double Width {get;}
    public double Height {get;}
    public double AspectRatio {get;}
    ...
}

Then, we need to identify paper types. An enum seems the ideal choice here:

public enum PaperSizes
{
    A4,
    Letter,
    ...
}

Then we can create our dictionary:

private static readonly Dictionary<PaperSizes, PaperDetails> _paperTypes = 
    new Dictionary<PaperSizes, PaperDetails>
    {
        [PaperSizes.A4] = new  PaperDetails(297, 420),
        [PaperSizes.Letter] = new PaperDetails(270, 200),
        ...
    };

Finally, we just need a static class to encapsulate that dictionary and to provide read-only access to it:

public static class PaperDetailsPerSize
{
    private static readonly Dictionary<PaperSizes, PaperDetails> _paperTypes = 
        new Dictionary<PaperSizes, PaperDetails>
        {
            [PaperSizes.A4] = new  PaperDetails(297, 420),
            [PaperSizes.Letter] = new PaperDetails(270, 200),
            ...
        };

    public static PaperDetails GetPaperDetails(PaperSizes size) => _paperTypes[size];
}

Job done and no need to worry about static classes not be able to implement interfaces. We didn't use constants (other than the width and height values, which are value, not named, constants). If that's a concern, then create a bunch of named constants to define those values and populate the dictionary with them.

  • I would probably need to avoid calculation and enter the values manually because of some messed-up API that uses those values, but this is very much what I'm looking for. I already use that enum, forgot to mention it. – Nemanja Petrović May 4 '18 at 9:50
1

Rather then going with constants, you could create an immutable non-static class (with get-only properties), and provide a bunch of predefined instances. It doesn't really have to inherit anything, or implement any interface, especially if it only stores these values and doesn't have any behavior. If the class is fairy small, consider making it a struct (see this), and providing a custom implementation for GetHashCode and Equals. As for how to provide these predefined values - you could make another class with a bunch of static factory methods (or properties - A4, Letter, etc.) that return the appropriate instance (creating it on the fly; alternatively, you could instantiate all in advance, and just return existing instances).

  • 1
    Another way to provide the values to clients is to use an enum and a dictionary - see David Arno's answer. That's probably less work, and possibly more flexible then a class with static properties I mentioned above. – Filip Milovanović May 4 '18 at 9:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.