Comments (3)
I spent some time thinking on this, with the hardest part being "what is a feature". After reading too many OGC docs, I found that a "Feature" is defined as part of GML, section 9.
If we go by what GML says then a Feature is simply an object, with some optionally predefined properties and a geometry.
I almost feel like IFeature could just have a geometry and an IReadOnlyDictionary<string, object>
for properties. For things that have predefined properties additional interfaces or just implementations would work. so something like:
interface IFeature
{
Geometry Geometry { get; set; }
IReadOnlyDictionary<string, object> Attributes { get; }
}
// For GPX for example
interface IWaypointFeature : IFeature
{
int Elevation { get; set; }
DateTimeOffset Time { get; set; }
// ...
}
from nettopologysuite.features.
IAttributesTable
has 7 function and a property to implement, IDictionary<string, object>
has lots more.
For specific classes implementing IFeature
I think the current approach is better.
from nettopologysuite.features.
Can
IAttributesTable
/AttributesTable
be replaced with justIDictionary<string, object>
directly on theFeature
class?
IAttributesTable
has 7 function and a property to implement,IDictionary<string, object>
has lots more.
For better or for worse, IDictionary<string, object>
is the standard interface for the kind of object that we need, and IMO that outweighs the concern of wanting to keep things simpler for implementers.
Agreed, though, custom implementations of IDictionary<TKey, TValue>
aren't easy. If it's important to support custom implementations, then perhaps we could help solve that by offering an abstract base class that implements the interface?
1 hour or so (completely untested) got me this, which only requires implementing 5 members:
public abstract class EasierDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>, IDictionary<TKey, TValue>
{
protected EasierDictionary()
{
Keys = new KeyCollection(this);
Values = new ValueCollection(this);
}
public abstract int Count { get; }
public abstract IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator();
public abstract void Clear();
protected abstract bool GetOrRemoveValue(TKey key, out TValue value, bool remove);
protected abstract bool SetValue(TKey key, TValue value, bool onlyIfMissing);
public KeyCollection Keys { get; }
ICollection<TKey> IDictionary<TKey, TValue>.Keys => Keys;
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
public ValueCollection Values { get; }
ICollection<TValue> IDictionary<TKey, TValue>.Values => Values;
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
public IEqualityComparer<TKey> KeyComparer { get; set; }
public IEqualityComparer<TValue> ValueComparer { get; set; }
public TValue this[TKey key]
{
get => GetOrRemoveValue(key, out var value, false) ? value : throw new KeyNotFoundException();
set => SetValue(key, value, false);
}
public bool ContainsKey(TKey key) => GetOrRemoveValue(key, out _, false);
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
foreach (var kvp in this)
{
array[arrayIndex++] = kvp;
}
}
public void Add(TKey key, TValue value)
{
if (SetValue(key, value, true))
{
throw new ArgumentException("", nameof(key));
}
}
public bool Remove(TKey key) => GetOrRemoveValue(key, out _, true);
public bool TryGetValue(TKey key, out TValue value) => GetOrRemoveValue(key, out value, false);
void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> kvp) => Add(kvp.Key, kvp.Value);
bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
{
if (!GetOrRemoveValue(item.Key, out var value, false))
{
return false;
}
var valueComparer = ValueComparer;
if (default(TValue) == null)
{
// https://github.com/dotnet/coreclr/issues/17273
valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
}
return valueComparer is null
? EqualityComparer<TValue>.Default.Equals(item.Value, value)
: valueComparer.Equals(item.Value, value);
}
bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
{
if (!TryGetValue(item.Key, out var value))
{
return false;
}
var valueComparer = ValueComparer;
if (default(TValue) == null)
{
// https://github.com/dotnet/coreclr/issues/17273
valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
}
if (valueComparer is null)
{
if (!EqualityComparer<TValue>.Default.Equals(item.Value, value))
{
return false;
}
}
else
{
if (!valueComparer.Equals(item.Value, value))
{
return false;
}
}
return GetOrRemoveValue(item.Key, out _, true);
}
bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly => false;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public sealed class KeyCollection : ICollection<TKey>
{
internal readonly EasierDictionary<TKey, TValue> _dict;
public KeyCollection(EasierDictionary<TKey, TValue> dict) => _dict = dict;
public int Count => _dict.Count;
public void CopyTo(TKey[] array, int arrayIndex)
{
foreach (var kvp in _dict)
{
array[arrayIndex++] = kvp.Key;
}
}
public Enumerator GetEnumerator() => new Enumerator(_dict);
bool ICollection<TKey>.IsReadOnly => true;
IEnumerator<TKey> IEnumerable<TKey>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
bool ICollection<TKey>.Contains(TKey item) => _dict.ContainsKey(item);
void ICollection<TKey>.Add(TKey item) => throw new NotSupportedException("");
void ICollection<TKey>.Clear() => throw new NotSupportedException("");
bool ICollection<TKey>.Remove(TKey item) => throw new NotSupportedException("");
public struct Enumerator : IEnumerator<TKey>
{
private readonly IEnumerator<KeyValuePair<TKey, TValue>> _enumerator;
internal Enumerator(EasierDictionary<TKey, TValue> dict) => _enumerator = dict.GetEnumerator();
public TKey Current => _enumerator.Current.Key;
object IEnumerator.Current => Current;
public void Dispose() => _enumerator.Dispose();
public bool MoveNext() => _enumerator.MoveNext();
public void Reset() => _enumerator.Reset();
}
}
public sealed class ValueCollection : ICollection<TValue>
{
private readonly EasierDictionary<TKey, TValue> _dict;
internal ValueCollection(EasierDictionary<TKey, TValue> dict) => _dict = dict;
public int Count => _dict.Count;
public void CopyTo(TValue[] array, int arrayIndex)
{
foreach (var kvp in _dict)
{
array[arrayIndex++] = kvp.Value;
}
}
public Enumerator GetEnumerator() => new Enumerator(_dict);
bool ICollection<TValue>.IsReadOnly => true;
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
bool ICollection<TValue>.Contains(TValue item)
{
var valueComparer = _dict.ValueComparer;
if (default(TValue) == null)
{
// https://github.com/dotnet/coreclr/issues/17273
valueComparer = valueComparer ?? EqualityComparer<TValue>.Default;
}
if (valueComparer is null)
{
foreach (var kvp in _dict)
{
if (EqualityComparer<TValue>.Default.Equals(kvp.Value, item))
{
return true;
}
}
}
else
{
foreach (var kvp in _dict)
{
if (valueComparer.Equals(kvp.Value, item))
{
return true;
}
}
}
return false;
}
void ICollection<TValue>.Add(TValue item) => throw new NotSupportedException("");
void ICollection<TValue>.Clear() => throw new NotSupportedException("");
bool ICollection<TValue>.Remove(TValue item) => throw new NotSupportedException("");
public struct Enumerator : IEnumerator<TValue>
{
private readonly IEnumerator<KeyValuePair<TKey, TValue>> _enumerator;
internal Enumerator(EasierDictionary<TKey, TValue> dict) => _enumerator = dict.GetEnumerator();
public TValue Current => _enumerator.Current.Value;
object IEnumerator.Current => Current;
public void Dispose() => _enumerator.Dispose();
public bool MoveNext() => _enumerator.MoveNext();
public void Reset() => _enumerator.Reset();
}
}
}
from nettopologysuite.features.
Related Issues (12)
- Setup build HOT 3
- 2.0 breaking change in AttributesTable ctor HOT 4
- FeatureCollection and XMLFormatter HOT 1
- How to test IAttributesTable for for thread safety issues? HOT 1
- IAttributesTable could support read-only instances better
- `GetOptionalId` is not consistent between implementations HOT 8
- 1.15 Release? HOT 1
- Simplify fetching values for optional attributes in (I)AttributesTable HOT 1
- Update to latest NTS Core HOT 2
- Remove CRS stuff HOT 2
- Add FeatureCollection ctor with IList<Feature> parameter HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from nettopologysuite.features.