Global type aliases in C#
Asked Answered
W

1

9

let me start right away with the code:

class Item {
    public int highestBuyOffer;
    public int lowestSellOffer;
    [...]
}

I would like to prevent people using this class from accidently assigning a buy offer value to a sell offer value and the other way round (like someBuyOffer = someSellOffer). That's why I want to create my own types:

class Item {
    public BuyOffer highestBuyOffer;
    public SellOffer lowestSellOffer;
    [...]
}

Creating a struct for it seems overkill, as these both of values should behave exactly like an int.

The using directive is not what I want because:

  1. It is only valid for one file
  2. It does not count as a type, it's just a synonym
Willetta answered 30/12, 2013 at 6:4 Comment(4)
Why are you using public fields instead of properties in the class? In any event, without knowing more about the requirements, if the logic to tell the difference is simple, set them up as properties and do the check there. If the logic is more complex, make the fields private and settable only via a method that implements the logic.Putrescible
You don't actually want both values to behave exactly like an int, because if they did, then a valid operation would be to assign one to the other! (Since an int can be assigned to an int.) You need to be more precise what operations you want to allow and set up the striut to allow exactly those operations.Quirk
I think feature you are looking for in your particular sample is version of "units of measurements" (i.e. as in Units of measure in C# answer). I think you'd have to create type with all operations you are interested in to support what you want (check Custom compile-time checks to see how you can have one implementation in generic class).Bakst
All I want is a compiler error if I try to assing one to the other.Willetta
B
4

I made this class to cover identical needs:

public class NamedInt : IComparable<int>, IEquatable<int>
{
    internal int Value { get; }

    protected NamedInt() { }
    protected NamedInt(int val) { Value = val; }
    protected NamedInt(string val) { Value = Convert.ToInt32(val); }

    public static implicit operator int (NamedInt val) { return val.Value; }

    public static bool operator ==(NamedInt a, int b) { return a?.Value == b; }
    public static bool operator ==(NamedInt a, NamedInt b) { return a?.Value == b?.Value; }
    public static bool operator !=(NamedInt a, int b) { return !(a==b); }
    public static bool operator !=(NamedInt a, NamedInt b) { return !(a==b); }

    public bool Equals(int other) { return Equals(new NamedInt(other)); }
    public override bool Equals(object other) {
        if ((other.GetType() != GetType() && other.GetType() != typeof(string))) return false;
        return Equals(new NamedInt(other.ToString()));
    }
    private bool Equals(NamedInt other) {
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return Equals(Value, other.Value);
    }

    public int CompareTo(int other) { return Value - other; }
    public int CompareTo(NamedInt other) { return Value - other.Value; }

    public override int GetHashCode() { return Value.GetHashCode(); }

    public override string ToString() { return Value.ToString(); }
}

And to consume it in your case:

public class BuyOffer: NamedInt {
    public BuyOffer(int value) : base(value) { }
    public static implicit operator BuyOffer(int value) { return new BuyOffer(value); }
}

public class SellOffer: NamedInt {
    public SellOffer(int value) : base(value) { }
    public static implicit operator SellOffer(int value) { return new SellOffer(value); }
}

If you need to be able to serialize it (Newtonsoft.Json), let me know and I'll add the code.

Birdlime answered 8/12, 2015 at 0:11 Comment(1)
Just...wow. Good idea? Bad idea? ...The judgement lies in the eye of the beholderFricke

© 2022 - 2024 — McMap. All rights reserved.