Я работаю с API геокодирования и должен представлять координату возвращенной точки как пару широты/долготы. Однако я не уверен, использовать ли для этого структуру или класс. Моя первоначальная мысль заключалась в том, чтобы использовать структуру, но в С# они, как правило, не одобряются (например, Jon Skeet упоминает в этом ответе, что "я почти никогда не определяю пользовательские структуры" ). Производительность и использование памяти не являются критическими факторами в приложении.
До сих пор я придумал эти две реализации на основе простого интерфейса:
Интерфейс
public interface ILatLng
{
double Lat { get; }
double Lng { get; }
}
Внедрение класса LatLng
public class CLatLng : ILatLng
{
public double Lat { get; private set; }
public double Lng { get; private set; }
public CLatLng(double lat, double lng)
{
this.Lat = lat;
this.Lng = lng;
}
public override string ToString()
{
return String.Format("{0},{1}", this.Lat, this.Lng);
}
public override bool Equals(Object obj)
{
if (obj == null)
return false;
CLatLng latlng = obj as CLatLng;
if ((Object)latlng == null)
return false;
return (this.Lat == latlng.Lat) && (this.Lng == latlng.Lng);
}
public bool Equals(CLatLng latlng)
{
if ((object)latlng == null)
return false;
return (this.Lat == latlng.Lat) && (this.Lng == latlng.Lng);
}
public override int GetHashCode()
{
return (int)Math.Sqrt(Math.Pow(this.Lat, 2) * Math.Pow(this.Lng, 2));
}
}
Реализация проекта LatLng
public struct SLatLng : ILatLng
{
private double _lat;
private double _lng;
public double Lat
{
get { return _lat; }
set { _lat = value; }
}
public double Lng
{
get { return _lng; }
set { _lng = value; }
}
public SLatLng(double lat, double lng)
{
this._lat = lat;
this._lng = lng;
}
public override string ToString()
{
return String.Format("{0},{1}", this.Lat, this.Lng);
}
}
Выполняя некоторые тесты, я пришел к следующим выводам:
-
У структуры всегда есть конструктор без параметров, что означает, что вы не можете заставить его быть созданным с помощью конструктора, который ожидает два свойства (для lat и lng), как вы можете, с классом.
-
Структура (являющаяся типом значения) никогда не может быть нулевой, поэтому всегда будет содержать значение. Но при реализации интерфейса вы все равно можете делать такие вещи:
ILatLng s = new SLatLng(); s = null;
Так ли имеет смысл, чтобы структура использовала интерфейс в этом случае?
-
Если я использую struct, мне нужно переопределить
Equals
,GetHashCode()
и т.д.? Мои тесты показывают, что сравнения работают правильно, не делая этого (в отличие от класса) - так ли это необходимо? -
Я чувствую себя более "комфортно" с помощью классов, так что лучше всего просто придерживаться их, поскольку я больше знаю, как они себя ведут? Будут ли люди, использующие мой код, путать семантику значений типа, особенно при работе с интерфейсом?
-
В реализации
CLatLng
выполняется ли переопределениеGetHashCode()
в порядке? Я "украл" это из этой статьи, поэтому не уверен!
Любая помощь или совет с благодарностью получили!