Новое определение типа в C#

Я ищу возможности, чтобы определить новый тип и использовать его в C#, как показано ниже:

определение класса:

public class Position
{
    public double180 Longitude { get; set; } // double180 is a type within a range -180 and 180
    public double90 Latitude { get; set; } // double90 is a type within a range of -90 and 90
}

использование:

var position = new Position
{
     Longitude = 45,
     Latitude = 96 // This line should give an error while initializing the object
};

7 ответов


тип может быть излишним, но если вы хотите один, это хорошее начало:

struct Double180 : IEquatable<Double180>
{
    private readonly double value;

    public Double180(double d)
    {
        if (d < -180 || d > 180)
        {
            throw new ArgumentOutOfRangeException("d");
        }

        this.value = d;
    }

    public static implicit operator double(Double180 d)
    {
        return d.value;
    }

    public static explicit operator Double180(double d)
    {
        return new Double180(d);
    }

    public override string ToString()
    {
        return this.value.ToString();
    }

    public bool Equals(Double180 other)
    {
        return this.value == other.value;
    }

    public override bool Equals(object obj)
    {
        return obj is Double180 && this.Equals((Double180)obj);
    }

    public override int GetHashCode()
    {
        return this.value.GetHashCode();
    }

    public static bool operator ==(Double180 a, Double180 b)
    {
        return a.Equals(b);
    }

    public static bool operator !=(Double180 a, Double180 b)
    {
        return !a.Equals(b);
    }
}

конечно, есть еще много интерфейсов для реализации, например IConvertible и IComparable<Double180> было бы неплохо.

как вы можете видеть, вы знаете, где это начинается, но вы не знаете, где она заканчивается.

валидатор сеттера, как было предложено другими ответами, может быть лучшей идеей.


для этого вам не обязательно нужен новый тип. Вместо использования свойства auto можно вручную написать сеттер, который проверяет значение:

public double Latitude
{
    get
    {
        return mLatitude;
    }

    set
    {
        if (value > 90 || value < -90)
        {
            throw new ArgumentOutOfRangeException("Invalid latitude");
        }

        mLatitude = value;
    }
}

private double mLatitude;

Если вы хотите повторно использовать этот код, вы можете определить свой собственный тип и использовать в нем вышеуказанный сеттер; затем укажите соответствующий конструктор и операторы преобразования.


вероятно, вам было бы лучше добавить систему.ComponentModel.DataAnnotations и использование [диапазон] так:

public class Position
{
    [Range(-180, 180)]
    public double Longitude { get; set; }

    [Range(-90, 90)]
    public double Latitude { get; set; }
}

использовать double и попросите сеттера проверить значение:

private double _longitude;
public double Longitude
{
    get
    {
        return _longitude;
    }
    set
    {
        if(value < -180 || value > 180)
        {
            throw new ArgumentException("value");
        }
        _longitude = value;
    }
}

добавьте шаг проверки в сеттер:

private double m_Latitude;

public double Latitude
{
  get{return m_Latitude;}

  set
  {
    if(value < -90 || value > 90) throw new ArgumentException("value");

    m_Latitude = value;
  }
}

обратите внимание, что при предоставлении реализации свойства необходимо добавить переменную-член для хранения значения базового свойства.


Я в основном получил идею: проверка ввода внутри сеттера. Когда дело доходит до определения типа, кажется, что структуры просто лучшие. Итак, наконец, я буду использовать ниже в своем проекте.

public struct Coordinate
{
    private readonly double _x;
    private readonly double _y;

    /// <summary>
    /// Longitude
    /// </summary>
    public double X
    {
        get { return _x; }
    }

    /// <summary>
    /// Latitude
    /// </summary>
    public double Y
    {
        get { return _y; }
    }

    /// <summary>
    /// Initiates a new coordinate.
    /// </summary>
    /// <param name="x">Longitude [-180, 180]</param>
    /// <param name="y">Latitude [-90, 90]</param>
    public Coordinate(double x, double y)
    {
        if (x < -180 || x > 180)
            throw new ArgumentOutOfRangeException(
                "x", "Longitude value must be in range of -180 and 180.");

        if (y < -90 || y > 90)
            throw new ArgumentOutOfRangeException(
                "y", "Latitude value must be in range of -90 and 90.");

        _x = x;
        _y = y;
    }
}

тогда я буду использовать вот так

var position = new Coordinate(46.32, 34.23);

спасибо всем за ценные комментарии.


мне нравится, что документация является частью системы:

public class Position
{
    /// <summary>
    /// ...
    /// 
    /// A value within a range -180 and 180
    /// </summary>
    public double Longitude { get; set; }

    /// <summary>
    /// ...
    /// 
    /// A value within a range -90 and 180
    /// </summary>
    public double Latitude { get; set; }
}

все зависимые модули должны быть протестированы в соответствии со спецификацией их зависимостей.