//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner willa // @backupOwner Microsoft //------------------------------------------------------------------------------ using System.Data.Spatial; using System.Data.Metadata.Edm; namespace System.Data.SqlClient.Internal { /// /// Adapter interface to make working with instances of or easier. /// Implementing types wrap instances of DbGeography/DbGeometry and allow them to be consumed in a common way. /// This interface is implemented by wrapping types for two reasons: /// 1. The DbGeography/DbGeometry classes cannot directly implement internal interfaces because their members are virtual (behavior is not guaranteed). /// 2. The wrapping types ensure that instances of IDbSpatialValue handle the s thrown /// by any unimplemented members of derived DbGeography/DbGeometry types that correspond to the properties and methods declared in the interface. /// internal interface IDbSpatialValue { bool IsGeography { get; } PrimitiveTypeKind PrimitiveType { get; } object ProviderValue { get; } int? CoordinateSystemId { get; } string WellKnownText { get; } byte[] WellKnownBinary { get; } string GmlString { get; } Exception NotSqlCompatible(); } internal static class IDbSpatialValueExtensionMethods { /// /// Returns an instance of that wraps the specified value. /// IDbSpatialValue members are guaranteed not to throw the s caused by unimplemented members of their wrapped values. /// /// The geography instance to wrap /// An instance of that wraps the specified geography value internal static IDbSpatialValue AsSpatialValue(this DbGeography geographyValue) { if (geographyValue == null) { return null; } return new DbGeographyAdapter(geographyValue); } /// /// Returns an instance of that wraps the specified value. /// IDbSpatialValue members are guaranteed not to throw the s caused by unimplemented members of their wrapped values. /// /// The geometry instance to wrap /// An instance of that wraps the specified geometry value internal static IDbSpatialValue AsSpatialValue(this DbGeometry geometryValue) { if (geometryValue == null) { return null; } return new DbGeometryAdapter(geometryValue); } } internal struct DbGeographyAdapter : IDbSpatialValue { private readonly DbGeography value; internal DbGeographyAdapter(DbGeography geomValue) { this.value = geomValue; } private TResult NullIfNotImplemented(Func accessor) where TResult : class { try { return accessor(this.value); } catch (NotImplementedException) { return null; } } private int? NullIfNotImplemented(Func accessor) { try { return accessor(this.value); } catch (NotImplementedException) { return null; } } public bool IsGeography { get { return true; } } public PrimitiveTypeKind PrimitiveType { get { return PrimitiveTypeKind.Geography; } } public object ProviderValue { get { return NullIfNotImplemented(geog => geog.ProviderValue); } } public int? CoordinateSystemId { get { return NullIfNotImplemented(geog => geog.CoordinateSystemId); } } public string WellKnownText { get { return NullIfNotImplemented(geog => geog.AsTextIncludingElevationAndMeasure()) ?? NullIfNotImplemented(geog => geog.AsText()); // better than nothing if the provider doesn't support AsTextIncludingElevationAndMeasure } } public byte[] WellKnownBinary { get { return NullIfNotImplemented(geog => geog.AsBinary()); } } public string GmlString { get { return NullIfNotImplemented(geog => geog.AsGml()); } } public Exception NotSqlCompatible() { return EntityUtil.GeographyValueNotSqlCompatible(); } } internal struct DbGeometryAdapter : IDbSpatialValue { private readonly DbGeometry value; internal DbGeometryAdapter(DbGeometry geomValue) { this.value = geomValue; } private TResult NullIfNotImplemented(Func accessor) where TResult : class { try { return accessor(this.value); } catch (NotImplementedException) { return null; } } private int? NullIfNotImplemented(Func accessor) { try { return accessor(this.value); } catch (NotImplementedException) { return null; } } public bool IsGeography { get { return false; } } public PrimitiveTypeKind PrimitiveType { get { return PrimitiveTypeKind.Geometry; } } public object ProviderValue { get { return NullIfNotImplemented(geom => geom.ProviderValue); } } public int? CoordinateSystemId { get { return NullIfNotImplemented(geom => geom.CoordinateSystemId); } } public string WellKnownText { get { return NullIfNotImplemented(geom => geom.AsTextIncludingElevationAndMeasure()) ?? NullIfNotImplemented(geom => geom.AsText()); // better than nothing if the provider doesn't support AsTextIncludingElevationAndMeasure } } public byte[] WellKnownBinary { get { return NullIfNotImplemented(geom => geom.AsBinary()); } } public string GmlString { get { return NullIfNotImplemented(geom => geom.AsGml()); } } public Exception NotSqlCompatible() { return EntityUtil.GeometryValueNotSqlCompatible(); } } }