C# Client Library
A C# Client Library for the AnalyzeRe REST API
Loading...
Searching...
No Matches
Reference[T].cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Runtime.Serialization;
4
8using RestSharp;
9
10// ReSharper disable NonReadonlyMemberInGetHashCode
11// We only compute the hashCode the first time it's needed, then never modify it.
12// Furthermore, the ref_id of a reference should never be changed after construction,
13// it's only modifiable for deserialization purposes.
14namespace AnalyzeRe
15{
18 [APITypeAlias("Reference")]
20 {
21 #region Private Properties
23 private int? _hashCode;
24
25 // Stores the object that this reference refers to, if it has been resolved.
26 private T _value;
27
30 private static readonly string TypeCollectionName;
31
34 private readonly string _localCollectionName;
35 #endregion Private Properties
36
37 #region Public Properties
40 public string CollectionName => _localCollectionName ?? TypeCollectionName;
41
44 public bool resolved { get; private set; }
45
49 public Type ResourceType => _value?.GetType() ?? typeof(T);
50
54 [Obsolete("This property has the potentially unexpected side-effect of resolving the " +
55 "reference (an expensive network operation) if it is not already resolved. " +
56 "Use the more explicit GetValue() or Resolve() methods instead.")]
57 public T Value
58 {
59 get
60 {
61 if (!resolved)
62 Resolve();
63 return _value;
64 }
65 }
66 #endregion Public Properties
67
68 #region Constructors
71 static Reference()
72 {
73 try
74 {
75 TypeCollectionName = API.GetCollectionName<T>();
76 }
77 catch (Exception)
78 {
79 TypeCollectionName = null;
80 }
81 }
82
86 public Reference(string ref_id) : this(ref_id, null) { }
87
92 public Reference(string ref_id, string href)
93 : base(ref_id, href)
94 {
95 resolved = false;
96 // Hack: ARE-5975: Nested LayerView references must identify their type for
97 // "sink" and "sources" references, so that we can distinguish them from layer references.
98 // TODO: See if there's a better way to do this only in the context of nested layers.
99 reference_type = this is IReference<ILayerView> ? "LayerView" :
100 this is IReference<ILayer> ? "Layer" : null;
101
102 // Determine the collection name based on the href if one is available.
103 if (href == null) return;
104 try
105 {
106 _localCollectionName = API.GetCollectionNameFromResourceHref(href);
107 }
108 catch (Exception e)
109 {
110 throw new ArgumentException("The specified href: {href} did not contain a " +
111 "discernible collection name. Expecting something like " +
112 "https://apiurl.net/collection_name/guid", e);
113 }
114 }
115
121 {
122 // If the reference being copied matches the current type, check for a resolved value
124 {
125 if (otherTyped.resolved)
126 TryResolveSelf(otherTyped.GetValue());
127 }
128 // Otherwise, if the reference being copied has any type and is resolved,
129 // copy the resolved value if it can be cast to the current type.
131 {
132 if (otherWeaklyTyped.resolved && otherWeaklyTyped.GetValue() is T asTValue)
133 TryResolveSelf(asTValue);
134 }
135 }
136
139 public Reference(T value) : this(value?.id)
140 {
141 TryResolveSelf(value);
142 }
143
147 private bool TryResolveSelf(T value)
148 {
149 _value = value;
150 if (value == null) return false;
151 // If our href property isn't set, we can set it now (for convenience)
152 if (href == null)
153 href = GuessHref(value.id, value);
154 resolved = true;
155 return true;
156 }
157 #endregion Constructors
158
159 #region Static Methods
163 public static string GuessHref(string ref_id, T value = default(T))
164 {
165 if (TypeCollectionName == null && value == null)
166 throw new Exception("Cannot resolve the reference because the collection for " +
167 "resources of type " + typeof(T).NiceTypeName() + " could not be determined " +
168 "and no explicit reference value was provided.");
169
170 return String.IsNullOrWhiteSpace(ref_id) ? null : API.ServerURL +
171 (value?.collection_name ?? TypeCollectionName) + "/" + ref_id;
172 }
173 #endregion Static Methods
174
175 #region Public Methods
193 int? timeout = null,
194 bool updateCache = false)
195 {
197 return _value;
198 }
199
215 int? timeout = null,
216 bool updateCache = false)
217 {
218 // If already resolved, we may not need to do anything
219 if (resolved)
220 {
221 // If updating the cache, use the object's own getter to update it from the server.
222 if (updateCache)
223 _value = _value.Get(requestParameters, timeout);
224 return;
225 }
226 // If this reference isn't resolved, determine how best to resolve it.
228 if (resolvedCollectionName == null && href == null)
229 {
230 throw new Exception("Cannot resolve the reference because " +
231 "the href property has not been set and the collection for " +
232 $"resources of type {typeof(T).NiceTypeName()} could not be determined.");
233 }
234 // If the reference type is not instantiable, we can determine the expected type
235 // based on the href we will resolve the reference with.
236 Type expectedType = resolvedCollectionName != null ?
239
240 // If the type is generic, get the covariant base type that the expected type can be assigned to.
241 if (expectedType.IsGenericType)
243
244 // Now we will attempt to retrieve the resource from the server (and deserialize it to the desired type)
245 // in the most efficient way possible given the information available.
247
248 // If the expected type is more specific than the current reference class type,
249 // supply it as a runtime deserialize type parameter.
251 {
253 (T)API.RequestAndParse(expectedType, $"{resolvedCollectionName}/{ref_id}",
256 }
257 // Otherwise, use the class type and compile-time type parameter invocation.
258 else
259 {
261 API.RequestAndParse<T>($"{resolvedCollectionName}/{ref_id}",
264 }
265
266 TryResolveSelf(resolvedValue);
267 }
268 #endregion Public Methods
269
270 #region Equality and Object overrides
273 public static explicit operator Reference<T>(T value) => new Reference<T>(value);
274
278 public override bool Equals(object obj)
279 {
280 // If the cast succeeded, we know these two objects share the same collection name
282 // If we reference an object by Id, test that both ids match
283 ((ref_id != null && Equals(ref_id, objReference.ref_id) &&
284 Equals(TypeCollectionName, objReference.CollectionName)) ||
285 // Otherwise, if both references are resolved, compare embedded values
286 (resolved && _value != null && objReference.resolved &&
287 Equals(_value, objReference.GetValue())));
288 // TODO: Should two references with a null ref_id and no value be equal?
289 }
290
293 public override int GetHashCode()
294 {
295 if (!_hashCode.HasValue)
296 {
297 // Include the collection name in the hash code to distinguish between
298 // resources in different collections with the same UUID (rare)
299 _hashCode = ref_id != null ? new { CollectionName, ref_id }.GetHashCode() :
300 // If the value is inlined (no reference id) then derive this
301 // reference's HashCode from the value itself instead.
302 resolved ? new { CollectionName, _value }.GetHashCode() :
303 base.GetHashCode();
304 }
305 return _hashCode.Value;
306 }
307
310 public override string ToString()
311 {
312 return ref_id ?? (resolved ? "new " + _value.GetType().NiceTypeName() : "(empty)");
313 }
314 #endregion Equality and Object overrides
315 }
316}
Describes a collection of resources which can be listed.
API methods / requests made available to the user.
static object GetUri(Type deserializeType, Uri href, IEnumerable< Parameter > requestParameters=null, int? timeout=null)
Perform a GET on an arbitrary resource by extracting the path and query parameters from a manually sp...
static object RequestAndParse(Type deserializeType, string resource, Method method, IEnumerable< Parameter > requestParameters=null, int? timeout=null)
Perform a REST request on the server and serializes the response to the desired run-time type.
static string GetCollectionName(Type requestType)
Gets the collection name for the given APIResource type, whether it's instantiable or not.
static string GetCollectionNameFromResourceHref(string href)
Return the collection name implied by the href for a given resource assuming the URL is in the format...
Implements the reference entity interface, with support for resolving references using lazy loading.
Reference(string ref_id, string href)
Creates a new reference that refers to an object of the current type, with the specified id but with ...
override string ToString()
Returns this reference's id, or value type if it has no id.
bool resolved
Indicates whether this reference has been resolved into an object.
void Resolve(IEnumerable< Parameter > requestParameters=null, int? timeout=null, bool updateCache=false)
Resolve this reference by retrieving the referenced object. If this reference is already resolved,...
override bool Equals(object obj)
Determines whether the two reference objects refer to the same object.
Reference(string ref_id)
Creates a new instance of this reference type that refers to an object with the specified id.
static string GuessHref(string ref_id, T value=default(T))
Attempts to guess the URL at which this resource can be resolved based on the resource collection nam...
T GetValue(IEnumerable< Parameter > requestParameters=null, int? timeout=null, bool updateCache=false)
Gets the resource that this reference refers to. If the reference has not previously been resolved,...
Type ResourceType
Returns the runtime type of resource this reference refers to, or the generic type parameter T if un...
override int GetHashCode()
Serves as a hash function for reference objects.
Reference(T value)
Creates a new reference to the specified resource.
Reference(IReference other)
Creates a new reference class that refers to the same object referred to by the other reference class...
string CollectionName
The name of the collection at which this resource resides.
T Value
Returns the object this reference refers to by resolving it with a request to the server.
Utility for resolving types given only the types name (Useful for parsing ambiguous JSON objects).
static Type ResolveBaseTypeByCollectionName(string collection)
Get the base type of object referenced by the supplied server URL.
static Type ResolveBaseTypeByURL(string href)
Get the base type of object referenced by the supplied server URL.
static Type GetGenericCovariantBase(Type T)
Returns the most strongly typed covariant base type which is assignable from the specified type T.
Interface for Base class used by all resources.
Base interface for all reference entities.
string ref_id
The id of the object being referred to.
Definition IReference.cs:17
string reference_type
In cases where a model can reference resources belonging to one of a number of collections,...
Definition IReference.cs:13
string href
The HREF that can be used to retrieve the object being referred to.
Definition IReference.cs:22