拆分 FreeSql 按需引用

This commit is contained in:
28810
2019-05-28 21:32:54 +08:00
parent 37ed28f7a0
commit f8e897e201
149 changed files with 945 additions and 4082 deletions

View File

@ -0,0 +1,63 @@
using FreeSql.Internal;
using MySql.Data.MySqlClient;
using SafeObjectPool;
using System;
using System.Collections;
using System.Data.Common;
using System.Text;
using System.Threading;
namespace FreeSql.MySql {
class MySqlAdo : FreeSql.Internal.CommonProvider.AdoProvider {
public MySqlAdo() : base(DataType.MySql) { }
public MySqlAdo(CommonUtils util, string masterConnectionString, string[] slaveConnectionStrings) : base(DataType.MySql) {
base._util = util;
if (!string.IsNullOrEmpty(masterConnectionString))
MasterPool = new MySqlConnectionPool("主库", masterConnectionString, null, null);
if (slaveConnectionStrings != null) {
foreach (var slaveConnectionString in slaveConnectionStrings) {
var slavePool = new MySqlConnectionPool($"从库{SlavePools.Count + 1}", slaveConnectionString, () => Interlocked.Decrement(ref slaveUnavailables), () => Interlocked.Increment(ref slaveUnavailables));
SlavePools.Add(slavePool);
}
}
}
static DateTime dt1970 = new DateTime(1970, 1, 1);
public override object AddslashesProcessParam(object param, Type mapType) {
if (param == null) return "NULL";
if (mapType != null && mapType != param.GetType())
param = Utils.GetDataReaderValue(mapType, param);
if (param is bool || param is bool?)
return (bool)param ? 1 : 0;
else if (param is string || param is char)
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
else if (param is Enum)
return string.Concat("'", param.ToString().Replace("'", "''"), "'"); //((Enum)val).ToInt64();
else if (decimal.TryParse(string.Concat(param), out var trydec))
return param;
else if (param is DateTime || param is DateTime?)
return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'");
else if (param is TimeSpan || param is TimeSpan?)
return ((TimeSpan)param).Ticks / 10;
else if (param is MygisGeometry)
return string.Concat("ST_GeomFromText('", (param as MygisGeometry).AsText().Replace("'", "''"), "')");
else if (param is IEnumerable) {
var sb = new StringBuilder();
var ie = param as IEnumerable;
foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z, mapType));
return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString();
}
return string.Concat("'", param.ToString().Replace("'", "''"), "'");
}
protected override DbCommand CreateCommand() {
return new MySqlCommand();
}
protected override void ReturnConnection(ObjectPool<DbConnection> pool, Object<DbConnection> conn, Exception ex) {
(pool as MySqlConnectionPool).Return(conn, ex);
}
protected override DbParameter[] GetDbParamtersByObject(string sql, object obj) => _util.GetDbParamtersByObject(sql, obj);
}
}

View File

@ -0,0 +1,177 @@
using MySql.Data.MySqlClient;
using SafeObjectPool;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace FreeSql.MySql {
class MySqlConnectionPool : ObjectPool<DbConnection> {
internal Action availableHandler;
internal Action unavailableHandler;
public MySqlConnectionPool(string name, string connectionString, Action availableHandler, Action unavailableHandler) : base(null) {
var policy = new MySqlConnectionPoolPolicy {
_pool = this,
Name = name
};
this.Policy = policy;
policy.ConnectionString = connectionString;
this.availableHandler = availableHandler;
this.unavailableHandler = unavailableHandler;
}
public void Return(Object<DbConnection> obj, Exception exception, bool isRecreate = false) {
if (exception != null && exception is MySqlException) {
try { if (obj.Value.Ping() == false) obj.Value.Open(); } catch { base.SetUnavailable(exception); }
}
base.Return(obj, isRecreate);
}
}
class MySqlConnectionPoolPolicy : IPolicy<DbConnection> {
internal MySqlConnectionPool _pool;
public string Name { get; set; } = "MySql MySqlConnection 对象池";
public int PoolSize { get; set; } = 100;
public TimeSpan SyncGetTimeout { get; set; } = TimeSpan.FromSeconds(10);
public TimeSpan IdleTimeout { get; set; } = TimeSpan.Zero;
public int AsyncGetCapacity { get; set; } = 10000;
public bool IsThrowGetTimeoutException { get; set; } = true;
public int CheckAvailableInterval { get; set; } = 5;
static ConcurrentDictionary<string, int> dicConnStrIncr = new ConcurrentDictionary<string, int>(StringComparer.CurrentCultureIgnoreCase);
private string _connectionString;
public string ConnectionString {
get => _connectionString;
set {
_connectionString = value ?? "";
var pattern = @"Max\s*pool\s*size\s*=\s*(\d+)";
var m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success == false || int.TryParse(m.Groups[1].Value, out var poolsize) == false || poolsize <= 0) poolsize = 100;
var connStrIncr = dicConnStrIncr.AddOrUpdate(_connectionString, 1, (oldkey, oldval) => oldval + 1);
PoolSize = poolsize + connStrIncr;
_connectionString = m.Success ?
Regex.Replace(_connectionString, pattern, $"Max pool size={PoolSize}", RegexOptions.IgnoreCase) :
$"{_connectionString};Max pool size={PoolSize}";
pattern = @"Connection\s*LifeTime\s*=\s*(\d+)";
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success) {
IdleTimeout = TimeSpan.FromSeconds(int.Parse(m.Groups[1].Value));
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
}
var minPoolSize = 0;
pattern = @"Min\s*pool\s*size\s*=\s*(\d+)";
m = Regex.Match(_connectionString, pattern, RegexOptions.IgnoreCase);
if (m.Success) {
minPoolSize = int.Parse(m.Groups[1].Value);
_connectionString = Regex.Replace(_connectionString, pattern, "", RegexOptions.IgnoreCase);
}
FreeSql.Internal.CommonUtils.PrevReheatConnectionPool(_pool, minPoolSize);
}
}
public bool OnCheckAvailable(Object<DbConnection> obj) {
if (obj.Value.State == ConnectionState.Closed) obj.Value.Open();
return obj.Value.Ping(true);
}
public DbConnection OnCreate() {
var conn = new MySqlConnection(_connectionString);
return conn;
}
public void OnDestroy(DbConnection obj) {
if (obj.State != ConnectionState.Closed) obj.Close();
obj.Dispose();
}
public void OnGet(Object<DbConnection> obj) {
if (_pool.IsAvailable) {
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && obj.Value.Ping() == false) {
try {
obj.Value.Open();
} catch (Exception ex) {
if (_pool.SetUnavailable(ex) == true)
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
}
}
}
}
async public Task OnGetAsync(Object<DbConnection> obj) {
if (_pool.IsAvailable) {
if (obj.Value.State != ConnectionState.Open || DateTime.Now.Subtract(obj.LastReturnTime).TotalSeconds > 60 && (await obj.Value.PingAsync()) == false) {
try {
await obj.Value.OpenAsync();
} catch (Exception ex) {
if (_pool.SetUnavailable(ex) == true)
throw new Exception($"【{this.Name}】状态不可用,等待后台检查程序恢复方可使用。{ex.Message}");
}
}
}
}
public void OnGetTimeout() {
}
public void OnReturn(Object<DbConnection> obj) {
}
public void OnAvailable() {
_pool.availableHandler?.Invoke();
}
public void OnUnavailable() {
_pool.unavailableHandler?.Invoke();
}
}
static class DbConnectionExtensions {
static DbCommand PingCommand(DbConnection conn) {
var cmd = conn.CreateCommand();
cmd.CommandTimeout = 5;
cmd.CommandText = "select 1";
return cmd;
}
public static bool Ping(this DbConnection that, bool isThrow = false) {
try {
PingCommand(that).ExecuteNonQuery();
return true;
} catch {
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
if (isThrow) throw;
return false;
}
}
async public static Task<bool> PingAsync(this DbConnection that, bool isThrow = false) {
try {
await PingCommand(that).ExecuteNonQueryAsync();
return true;
} catch {
if (that.State != ConnectionState.Closed) try { that.Close(); } catch { }
if (isThrow) throw;
return false;
}
}
}
}

View File

@ -0,0 +1,292 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
public struct MygisCoordinate2D : IEquatable<MygisCoordinate2D> {
public double X { get; }
public double Y { get; }
public MygisCoordinate2D(double x, double y) { X = x; Y = y; }
public bool Equals(MygisCoordinate2D c) => X == c.X && Y == c.Y;
public override int GetHashCode() => X.GetHashCode() ^ MygisGeometry.RotateShift(Y.GetHashCode(), sizeof(int) / 2);
public override bool Equals(object obj) => obj is MygisCoordinate2D && Equals((MygisCoordinate2D) obj);
public static bool operator ==(MygisCoordinate2D left, MygisCoordinate2D right) => Equals(left, right);
public static bool operator !=(MygisCoordinate2D left, MygisCoordinate2D right) => !Equals(left, right);
}
public abstract class MygisGeometry {
protected abstract int GetLenHelper();
internal int GetLen(bool includeSRID) => 5 + (SRID == 0 || !includeSRID ? 0 : 4) + GetLenHelper();
public uint SRID { get; set; } = 0;
internal static int RotateShift(int val, int shift) => (val << shift) | (val >> (sizeof(int) - shift));
public override string ToString() => this.AsText();
public string AsText() {
if (this is MygisPoint) {
var obj = this as MygisPoint;
return $"POINT({obj.X} {obj.Y})";
}
if (this is MygisLineString) {
var obj = this as MygisLineString;
return obj?.PointCount > 0 ? $"LINESTRING({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
}
if (this is MygisPolygon) {
var obj = (this as MygisPolygon).Where(z => z.Count() > 1 && z.First().Equals(z.Last()));
return obj.Any() ? $"POLYGON(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
}
if (this is MygisMultiPoint) {
var obj = this as MygisMultiPoint;
return obj?.PointCount > 0 ? $"MULTIPOINT({string.Join(",", obj.Select(a => $"{a.X} {a.Y}"))})" : null;
}
if (this is MygisMultiLineString) {
var obj = this as MygisMultiLineString;
return obj.LineCount > 0 ? $"MULTILINESTRING(({string.Join("),(", obj.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))}))" : null;
}
if (this is MygisMultiPolygon) {
var obj = (this as MygisMultiPolygon)?.Where(z => z.Where(y => y.Count() > 1 && y.First().Equals(y.Last())).Any());
return obj.Any() ? $"MULTIPOLYGON((({string.Join(")),((", obj.Select(d => string.Join("),(", d.Select(c => string.Join(",", c.Select(a => $"{a.X} {a.Y}"))))))})))" : null;
}
return base.ToString();
}
static readonly Regex regexMygisPoint = new Regex(@"\s*(-?\d+\.?\d*)\s+(-?\d+\.?\d*)\s*");
static readonly Regex regexSplit1 = new Regex(@"\)\s*,\s*\(");
static readonly Regex regexSplit2 = new Regex(@"\)\s*\)\s*,\s*\(\s*\(");
public static MygisGeometry Parse(string wkt) {
if (string.IsNullOrEmpty(wkt)) return null;
wkt = wkt.Trim();
if (wkt.StartsWith("point", StringComparison.CurrentCultureIgnoreCase)) return ParsePoint(wkt.Substring(5).Trim('(', ')'));
else if (wkt.StartsWith("linestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisLineString(ParseLineString(wkt.Substring(10).Trim('(', ')')));
else if (wkt.StartsWith("polygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisPolygon(ParsePolygon(wkt.Substring(7).Trim('(', ')')));
else if (wkt.StartsWith("multipoint", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPoint(ParseLineString(wkt.Substring(10).Trim('(', ')')));
else if (wkt.StartsWith("multilinestring", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiLineString(ParseMultiLineString(wkt.Substring(15).Trim('(', ')')));
else if (wkt.StartsWith("multipolygon", StringComparison.CurrentCultureIgnoreCase)) return new MygisMultiPolygon(ParseMultiPolygon(wkt.Substring(12).Trim('(', ')')));
throw new NotImplementedException($"MygisGeometry.Parse 未实现 \"{wkt}\"");
}
static MygisPoint ParsePoint(string str) {
var m = regexMygisPoint.Match(str);
if (m.Success == false) return null;
return new MygisPoint(double.TryParse(m.Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(m.Groups[2].Value, out tryd) ? tryd : 0);
}
static MygisCoordinate2D[] ParseLineString(string str) {
var ms = regexMygisPoint.Matches(str);
var points = new MygisCoordinate2D[ms.Count];
for (var a = 0; a < ms.Count; a++) points[a] = new MygisCoordinate2D(double.TryParse(ms[a].Groups[1].Value, out var tryd) ? tryd : 0, double.TryParse(ms[a].Groups[2].Value, out tryd) ? tryd : 0);
return points;
}
static MygisCoordinate2D[][] ParsePolygon(string str) {
return regexSplit1.Split(str).Select(s => ParseLineString(s)).Where(a => a.Length > 1 && a.First().Equals(a.Last())).ToArray();
}
static MygisLineString[] ParseMultiLineString(string str) {
return regexSplit1.Split(str).Select(s => new MygisLineString(ParseLineString(s))).ToArray();
}
static MygisPolygon[] ParseMultiPolygon(string str) {
return regexSplit2.Split(str).Select(s => new MygisPolygon(ParsePolygon(s))).ToArray();
}
}
public class MygisPoint : MygisGeometry, IEquatable<MygisPoint> {
MygisCoordinate2D _coord;
protected override int GetLenHelper() => 16;
public double X => _coord.X;
public double Y => _coord.Y;
public MygisPoint(double x, double y) {
_coord = new MygisCoordinate2D(x, y);
}
public bool Equals(MygisPoint other) => !ReferenceEquals(other, null) && _coord.Equals(other._coord);
public override bool Equals(object obj) => Equals(obj as MygisPoint);
public static bool operator ==(MygisPoint x, MygisPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
public static bool operator !=(MygisPoint x, MygisPoint y) => !(x == y);
public override int GetHashCode() => X.GetHashCode() ^ RotateShift(Y.GetHashCode(), sizeof(int) / 2);
}
public class MygisLineString : MygisGeometry, IEquatable<MygisLineString>, IEnumerable<MygisCoordinate2D> {
readonly MygisCoordinate2D[] _points;
protected override int GetLenHelper() => 4 + _points.Length * 16;
public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>) _points).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public MygisCoordinate2D this[int index] => _points[index];
public int PointCount => _points.Length;
public MygisLineString(IEnumerable<MygisCoordinate2D> points) {
_points = points.ToArray();
}
public MygisLineString(MygisCoordinate2D[] points) {
_points = points;
}
public bool Equals(MygisLineString other) {
if (ReferenceEquals(other, null)) return false;
if (_points.Length != other._points.Length) return false;
for (var i = 0; i < _points.Length; i++)
if (!_points[i].Equals(other._points[i])) return false;
return true;
}
public override bool Equals(object obj) => Equals(obj as MygisLineString);
public static bool operator ==(MygisLineString x, MygisLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
public static bool operator !=(MygisLineString x, MygisLineString y) => !(x == y);
public override int GetHashCode() {
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
foreach (var t in _points) ret ^= RotateShift(t.GetHashCode(), ret % sizeof(int));
return ret;
}
}
public class MygisPolygon : MygisGeometry, IEquatable<MygisPolygon>, IEnumerable<IEnumerable<MygisCoordinate2D>> {
readonly MygisCoordinate2D[][] _rings;
protected override int GetLenHelper() => 4 + _rings.Length * 4 + TotalPointCount * 16;
public MygisCoordinate2D this[int ringIndex, int pointIndex] => _rings[ringIndex][pointIndex];
public MygisCoordinate2D[] this[int ringIndex] => _rings[ringIndex];
public IEnumerator<IEnumerable<MygisCoordinate2D>> GetEnumerator() => ((IEnumerable<IEnumerable<MygisCoordinate2D>>) _rings).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public int RingCount => _rings.Length;
public int TotalPointCount => _rings.Sum(r => r.Length);
public MygisPolygon(MygisCoordinate2D[][] rings) {
_rings = rings;
}
public MygisPolygon(IEnumerable<IEnumerable<MygisCoordinate2D>> rings) {
_rings = rings.Select(x => x.ToArray()).ToArray();
}
public bool Equals(MygisPolygon other) {
if (ReferenceEquals(other, null)) return false;
if (_rings.Length != other._rings.Length) return false;
for (var i = 0; i < _rings.Length; i++) {
if (_rings[i].Length != other._rings[i].Length) return false;
for (var j = 0; j < _rings[i].Length; j++)
if (!_rings[i][j].Equals(other._rings[i][j])) return false;
}
return true;
}
public override bool Equals(object obj) => Equals(obj as MygisPolygon);
public static bool operator ==(MygisPolygon x, MygisPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
public static bool operator !=(MygisPolygon x, MygisPolygon y) => !(x == y);
public override int GetHashCode() {
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _rings.Length; i++)
for (var j = 0; j < _rings[i].Length; j++)
ret ^= RotateShift(_rings[i][j].GetHashCode(), ret % sizeof(int));
return ret;
}
}
public class MygisMultiPoint : MygisGeometry, IEquatable<MygisMultiPoint>, IEnumerable<MygisCoordinate2D> {
readonly MygisCoordinate2D[] _points;
protected override int GetLenHelper() => 4 + _points.Length * 21;
public IEnumerator<MygisCoordinate2D> GetEnumerator() => ((IEnumerable<MygisCoordinate2D>) _points).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public MygisCoordinate2D this[int indexer] => _points[indexer];
public int PointCount => _points.Length;
public MygisMultiPoint(MygisCoordinate2D[] points) {
_points = points;
}
public MygisMultiPoint(IEnumerable<MygisPoint> points) {
_points = points.Select(x => new MygisCoordinate2D(x.X, x.Y)).ToArray();
}
public MygisMultiPoint(IEnumerable<MygisCoordinate2D> points) {
_points = points.ToArray();
}
public bool Equals(MygisMultiPoint other) {
if (ReferenceEquals(other, null)) return false;
if (_points.Length != other._points.Length) return false;
for (var i = 0; i < _points.Length; i++)
if (!_points[i].Equals(other._points[i])) return false;
return true;
}
public override bool Equals(object obj) => Equals(obj as MygisMultiPoint);
public static bool operator ==(MygisMultiPoint x, MygisMultiPoint y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
public static bool operator !=(MygisMultiPoint x, MygisMultiPoint y) => !(x == y);
public override int GetHashCode() {
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _points.Length; i++) ret ^= RotateShift(_points[i].GetHashCode(), ret % sizeof(int));
return ret;
}
}
public sealed class MygisMultiLineString : MygisGeometry,
IEquatable<MygisMultiLineString>, IEnumerable<MygisLineString> {
readonly MygisLineString[] _lineStrings;
protected override int GetLenHelper() {
var n = 4;
for (var i = 0; i < _lineStrings.Length; i++) n += _lineStrings[i].GetLen(false);
return n;
}
public IEnumerator<MygisLineString> GetEnumerator() => ((IEnumerable<MygisLineString>) _lineStrings).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public MygisLineString this[int index] => _lineStrings[index];
public int LineCount => _lineStrings.Length;
internal MygisMultiLineString(MygisCoordinate2D[][] pointArray) {
_lineStrings = new MygisLineString[pointArray.Length];
for (var i = 0; i < pointArray.Length; i++)
_lineStrings[i] = new MygisLineString(pointArray[i]);
}
public MygisMultiLineString(MygisLineString[] linestrings) {
_lineStrings = linestrings;
}
public MygisMultiLineString(IEnumerable<MygisLineString> linestrings) {
_lineStrings = linestrings.ToArray();
}
public MygisMultiLineString(IEnumerable<IEnumerable<MygisCoordinate2D>> pointList) {
_lineStrings = pointList.Select(x => new MygisLineString(x)).ToArray();
}
public bool Equals(MygisMultiLineString other) {
if (ReferenceEquals(other, null)) return false;
if (_lineStrings.Length != other._lineStrings.Length) return false;
for (var i = 0; i < _lineStrings.Length; i++)
if (_lineStrings[i] != other._lineStrings[i]) return false;
return true;
}
public override bool Equals(object obj) => Equals(obj as MygisMultiLineString);
public static bool operator ==(MygisMultiLineString x, MygisMultiLineString y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
public static bool operator !=(MygisMultiLineString x, MygisMultiLineString y) => !(x == y);
public override int GetHashCode() {
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _lineStrings.Length; i++) ret ^= RotateShift(_lineStrings[i].GetHashCode(), ret % sizeof(int));
return ret;
}
}
public class MygisMultiPolygon : MygisGeometry, IEquatable<MygisMultiPolygon>, IEnumerable<MygisPolygon> {
readonly MygisPolygon[] _polygons;
protected override int GetLenHelper() {
var n = 4;
for (var i = 0; i < _polygons.Length; i++) n += _polygons[i].GetLen(false);
return n;
}
public IEnumerator<MygisPolygon> GetEnumerator() => ((IEnumerable<MygisPolygon>) _polygons).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public MygisPolygon this[int index] => _polygons[index];
public int PolygonCount => _polygons.Length;
public MygisMultiPolygon(MygisPolygon[] polygons) {
_polygons = polygons;
}
public MygisMultiPolygon(IEnumerable<MygisPolygon> polygons) {
_polygons = polygons.ToArray();
}
public MygisMultiPolygon(IEnumerable<IEnumerable<IEnumerable<MygisCoordinate2D>>> ringList) {
_polygons = ringList.Select(x => new MygisPolygon(x)).ToArray();
}
public bool Equals(MygisMultiPolygon other) {
if (ReferenceEquals(other, null)) return false;
if (_polygons.Length != other._polygons.Length) return false;
for (var i = 0; i < _polygons.Length; i++) if (_polygons[i] != other._polygons[i]) return false;
return true;
}
public override bool Equals(object obj) => obj is MygisMultiPolygon && Equals((MygisMultiPolygon) obj);
public static bool operator ==(MygisMultiPolygon x, MygisMultiPolygon y) => ReferenceEquals(x, null) ? ReferenceEquals(y, null) : x.Equals(y);
public static bool operator !=(MygisMultiPolygon x, MygisMultiPolygon y) => !(x == y);
public override int GetHashCode() {
var ret = 266370105;//seed with something other than zero to make paths of all zeros hash differently.
for (var i = 0; i < _polygons.Length; i++) ret ^= RotateShift(_polygons[i].GetHashCode(), ret % sizeof(int));
return ret;
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Text;
public static partial class MygisTypesExtensions {
/// <summary>
/// 测量两个经纬度的距离,返回单位:米
/// </summary>
/// <param name="that">经纬坐标1</param>
/// <param name="point">经纬坐标2</param>
/// <returns>返回距离(单位:米)</returns>
public static double Distance(this MygisPoint that, MygisPoint point) {
double radLat1 = (double)(that.Y) * Math.PI / 180d;
double radLng1 = (double)(that.X) * Math.PI / 180d;
double radLat2 = (double)(point.Y) * Math.PI / 180d;
double radLng2 = (double)(point.X) * Math.PI / 180d;
return 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin((radLat1 - radLat2) / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin((radLng1 - radLng2) / 2), 2))) * 6378137;
}
}