From 187f501a4dffcb3ee81933af44e2ef92cbb45fdd Mon Sep 17 00:00:00 2001
From: Ferdinando Papale <4850119+papafe@users.noreply.github.com>
Date: Mon, 12 Aug 2024 13:32:35 +0200
Subject: [PATCH] Added stub for unmanaged object dynamic api
---
.../Accessors/ManagedAccessor.cs | 4 +-
.../Accessors/UnmanagedAccessor.cs | 32 +++
.../Realm/Dynamic/DynamicManagedObjectApi.cs | 235 ++++++++++++++++++
Realm/Realm/Dynamic/DynamicObjectApi.cs | 194 +--------------
.../Dynamic/DynamicUnmanagedObjectApi.cs | 97 ++++++++
.../Database/RelaxedSchemaTests.cs | 2 +
6 files changed, 380 insertions(+), 184 deletions(-)
create mode 100644 Realm/Realm/Dynamic/DynamicManagedObjectApi.cs
create mode 100644 Realm/Realm/Dynamic/DynamicUnmanagedObjectApi.cs
diff --git a/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs b/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs
index c621787407..972734a4bc 100644
--- a/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs
+++ b/Realm/Realm/DatabaseTypes/Accessors/ManagedAccessor.cs
@@ -87,7 +87,7 @@ protected ManagedAccessor()
{
_hashCode = new(() => ObjectHandle!.GetObjHash());
_objectSchema = new(() => Realm!.Config.RelaxedSchema ? Metadata!.Schema.MakeCopyWithHandle(ObjectHandle!) : Metadata!.Schema);
- _dynamicObjectApi = new(() => new(this));
+ _dynamicObjectApi = new(() => new DynamicManagedObjectApi(this));
}
[MemberNotNull(nameof(Realm), nameof(ObjectHandle), nameof(Metadata))]
@@ -114,7 +114,7 @@ public RealmValue GetValue(string propertyName)
return ObjectHandle.GetValue(propertyName, Metadata, Realm);
}
- ///
+ /// AddDocs
public bool TryGetValue(string propertyName, out RealmValue value)
{
return ObjectHandle.TryGetValue(propertyName, Metadata, Realm, out value);
diff --git a/Realm/Realm/DatabaseTypes/Accessors/UnmanagedAccessor.cs b/Realm/Realm/DatabaseTypes/Accessors/UnmanagedAccessor.cs
index 4022e94cd4..378bbb7951 100644
--- a/Realm/Realm/DatabaseTypes/Accessors/UnmanagedAccessor.cs
+++ b/Realm/Realm/DatabaseTypes/Accessors/UnmanagedAccessor.cs
@@ -37,6 +37,9 @@ public abstract class UnmanagedAccessor : IRealmAccessor
private Action? _onNotifyPropertyChanged;
+ //TODO we could initialize this lazily
+ protected Dictionary _extraProperties = new();
+
///
public bool IsManaged => false;
@@ -93,6 +96,10 @@ public IQueryable GetBacklinks(string propertyName)
///
public abstract void SetValueUnique(string propertyName, RealmValue val);
+ public abstract bool TryGet(string propertyName, out RealmValue value);
+
+ public abstract bool Unset(string propertyName);
+
///
public virtual void SubscribeForNotifications(Action notifyPropertyChangedDelegate)
{
@@ -168,5 +175,30 @@ public override void SetValueUnique(string propertyName, RealmValue val)
{
throw new NotSupportedException("This should not be used for now");
}
+
+ public override bool TryGet(string propertyName, out RealmValue value)
+ {
+ return _extraProperties.TryGetValue(propertyName, out value);
+ }
+
+ public override bool Unset(string propertyName)
+ {
+ return _extraProperties.Remove(propertyName);
+ }
+
+ public bool TryGetExtraProperty(string propertyName, out RealmValue value)
+ {
+ return _extraProperties.TryGetValue(propertyName, out value);
+ }
+
+ public RealmValue GetExtraProperty(string propertyName)
+ {
+ return _extraProperties[propertyName];
+ }
+
+ public void SetExtraProperty(string propertyName, RealmValue val)
+ {
+ _extraProperties[propertyName] = val;
+ }
}
}
diff --git a/Realm/Realm/Dynamic/DynamicManagedObjectApi.cs b/Realm/Realm/Dynamic/DynamicManagedObjectApi.cs
new file mode 100644
index 0000000000..e4ec997625
--- /dev/null
+++ b/Realm/Realm/Dynamic/DynamicManagedObjectApi.cs
@@ -0,0 +1,235 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2024 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License")
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using Realms.Helpers;
+using Realms.Schema;
+
+namespace Realms
+{
+ ///
+ public class DynamicManagedObjectApi : DynamicObjectApi
+ {
+ private readonly ManagedAccessor _managedAccessor;
+
+ private readonly bool _isRelaxedSchema;
+
+ internal DynamicManagedObjectApi(ManagedAccessor managedAccessor)
+ {
+ _managedAccessor = managedAccessor;
+ _isRelaxedSchema = managedAccessor.Realm.Config.RelaxedSchema;
+ }
+
+ ///
+ public override RealmValue Get(string propertyName)
+ {
+ CheckGetPropertySuitability(propertyName);
+
+ return _managedAccessor.GetValue(propertyName);
+ }
+
+ ///
+ public override T Get(string propertyName)
+ {
+ return Get(propertyName).As();
+ }
+
+ ///
+ public override bool TryGet(string propertyName, out RealmValue propertyValue)
+ {
+ CheckGetPropertySuitability(propertyName);
+
+ return _managedAccessor.TryGetValue(propertyName, out propertyValue);
+ }
+
+ ///
+ public override bool TryGet(string propertyName, out T? propertyValue)
+ where T : default
+ {
+ var foundValue = TryGet(propertyName, out var val);
+ if (foundValue)
+ {
+ propertyValue = val.As();
+ return true;
+ }
+
+ propertyValue = default;
+ return false;
+ }
+
+ ///
+ public override void Set(string propertyName, RealmValue value)
+ {
+ if (GetModelProperty(propertyName, throwOnMissing: !_isRelaxedSchema) is Property property)
+ {
+ if (property.Type.IsComputed())
+ {
+ throw new NotSupportedException(
+ $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} (backlinks collection) and can't be set directly");
+ }
+
+ if (property.Type.IsCollection(out _))
+ {
+ throw new NotSupportedException(
+ $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} (collection) and can't be set directly.");
+ }
+
+ if (!property.Type.IsNullable() && value.Type == RealmValueType.Null)
+ {
+ throw new ArgumentException($"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} which is not nullable, but the supplied value is .");
+ }
+
+ if (!property.Type.IsRealmValue() && value.Type != RealmValueType.Null && property.Type.ToRealmValueType() != value.Type)
+ {
+ throw new ArgumentException($"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} but the supplied value is {value.AsAny()?.GetType().Name} ({value}).");
+ }
+
+ if (property.IsPrimaryKey)
+ {
+ _managedAccessor.SetValueUnique(propertyName, value);
+ return;
+ }
+ }
+
+ _managedAccessor.SetValue(propertyName, value);
+ }
+
+ ///
+ public override bool Unset(string propertyName)
+ {
+ return _managedAccessor.UnsetProperty(propertyName);
+ }
+
+ ///
+ public override IQueryable GetBacklinks(string propertyName)
+ {
+ var property = GetModelProperty(propertyName, PropertyTypeEx.IsComputed);
+
+ var resultsHandle = _managedAccessor.ObjectHandle.GetBacklinks(propertyName, _managedAccessor.Metadata);
+
+ var relatedMeta = _managedAccessor.Realm.Metadata[property.ObjectType!];
+ if (relatedMeta.Schema.BaseType == ObjectSchema.ObjectType.EmbeddedObject)
+ {
+ return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
+ }
+
+ return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
+ }
+
+ ///
+ public override IQueryable GetBacklinksFromType(string fromObjectType, string fromPropertyName)
+ {
+ Argument.Ensure(_managedAccessor.Realm.Metadata.TryGetValue(fromObjectType, out var relatedMeta), $"Could not find schema for type {fromObjectType}", nameof(fromObjectType));
+
+ var resultsHandle = _managedAccessor.ObjectHandle.GetBacklinksForType(relatedMeta.TableKey, fromPropertyName, relatedMeta);
+ if (relatedMeta.Schema.BaseType == ObjectSchema.ObjectType.EmbeddedObject)
+ {
+ return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
+ }
+
+ return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
+ }
+
+ ///
+ public override IList GetList(string propertyName)
+ {
+ var property = GetModelProperty(propertyName, PropertyTypeEx.IsList);
+
+ var result = _managedAccessor.ObjectHandle.GetList(_managedAccessor.Realm, propertyName, _managedAccessor.Metadata, property.ObjectType);
+ result.IsDynamic = true;
+ return result;
+ }
+
+ ///
+ public override ISet GetSet(string propertyName)
+ {
+ var property = GetModelProperty(propertyName, PropertyTypeEx.IsSet);
+
+ var result = _managedAccessor.ObjectHandle.GetSet(_managedAccessor.Realm, propertyName, _managedAccessor.Metadata, property.ObjectType);
+ result.IsDynamic = true;
+ return result;
+ }
+
+ ///
+ public override IDictionary GetDictionary(string propertyName)
+ {
+ var property = GetModelProperty(propertyName, PropertyTypeEx.IsDictionary);
+
+ var result = _managedAccessor.ObjectHandle.GetDictionary(_managedAccessor.Realm, propertyName, _managedAccessor.Metadata, property.ObjectType);
+ result.IsDynamic = true;
+ return result;
+ }
+
+ private void CheckGetPropertySuitability(string propertyName)
+ {
+ if (GetModelProperty(propertyName, throwOnMissing: !_isRelaxedSchema) is Property property)
+ {
+ if (property.Type.IsComputed())
+ {
+ throw new NotSupportedException(
+ $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} (backlinks collection) and can't be accessed using {nameof(Dynamic)}.{nameof(Get)}. Use {nameof(GetBacklinks)} instead.");
+ }
+
+ if (property.Type.IsCollection(out var collectionType) && collectionType == PropertyType.Set)
+ {
+ throw new NotSupportedException(
+ $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} and can't be accessed using {nameof(Dynamic)}.{nameof(Get)}. Use GetSet instead.");
+ }
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Property? GetModelProperty(string propertyName, bool throwOnMissing)
+ {
+ Argument.NotNull(propertyName, nameof(propertyName));
+
+ if (!_managedAccessor.ObjectSchema.TryFindModelProperty(propertyName, out var property))
+ {
+ if (throwOnMissing)
+ {
+ throw new MissingMemberException(_managedAccessor.ObjectSchema.Name, propertyName);
+ }
+
+ return null;
+ }
+
+ return property;
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private Property GetModelProperty(string propertyName, Func typeCheck, [CallerMemberName] string methodName = "")
+ {
+ Argument.NotNull(propertyName, nameof(propertyName));
+
+ if (!_managedAccessor.ObjectSchema.TryFindModelProperty(propertyName, out var property))
+ {
+ throw new MissingMemberException(_managedAccessor.ObjectSchema.Name, propertyName);
+ }
+
+ if (!typeCheck(property.Type))
+ {
+ throw new ArgumentException($"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} which can't be accessed using {methodName}.");
+ }
+
+ return property;
+ }
+ }
+}
diff --git a/Realm/Realm/Dynamic/DynamicObjectApi.cs b/Realm/Realm/Dynamic/DynamicObjectApi.cs
index 6115222d8b..43b87cff60 100644
--- a/Realm/Realm/Dynamic/DynamicObjectApi.cs
+++ b/Realm/Realm/Dynamic/DynamicObjectApi.cs
@@ -29,25 +29,10 @@ namespace Realms
/// A class that exposes a set of API to access the data in a managed RealmObject dynamically.
///
///
- public class DynamicObjectApi
+ public abstract class DynamicObjectApi
{
- private readonly ManagedAccessor _managedAccessor;
-
- private readonly bool _isRelaxedSchema;
-
- internal DynamicObjectApi(ManagedAccessor managedAccessor)
- {
- _managedAccessor = managedAccessor;
- _isRelaxedSchema = managedAccessor.Realm.Config.RelaxedSchema;
- }
-
//TODO Add docs
- public RealmValue Get(string propertyName)
- {
- CheckGetPropertySuitability(propertyName);
-
- return _managedAccessor.GetValue(propertyName);
- }
+ public abstract RealmValue Get(string propertyName);
///
/// Gets the value of the property and casts it to
@@ -63,32 +48,13 @@ public RealmValue Get(string propertyName)
/// Casting to is always valid. When the property is of type
/// object, casting to is always valid.
///
- public T Get(string propertyName)
- {
- return Get(propertyName).As();
- }
+ public abstract T Get(string propertyName);
//TODO Add docs
- public bool TryGet(string propertyName, out RealmValue propertyValue)
- {
- CheckGetPropertySuitability(propertyName);
-
- return _managedAccessor.TryGetValue(propertyName, out propertyValue);
- }
+ public abstract bool TryGet(string propertyName, out RealmValue propertyValue);
//TODO Add docs
- public bool TryGet(string propertyName, out T? propertyValue)
- {
- var foundValue = TryGet(propertyName, out var val);
- if (foundValue)
- {
- propertyValue = val.As();
- return true;
- }
-
- propertyValue = default;
- return false;
- }
+ public abstract bool TryGet(string propertyName, out T? propertyValue);
///
/// Sets the value of the property at to
@@ -96,47 +62,10 @@ public bool TryGet(string propertyName, out T? propertyValue)
///
/// The name of the property to set.
/// The new value of the property.
- public void Set(string propertyName, RealmValue value)
- {
- if (GetModelProperty(propertyName, throwOnMissing: !_isRelaxedSchema) is Property property)
- {
- if (property.Type.IsComputed())
- {
- throw new NotSupportedException(
- $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} (backlinks collection) and can't be set directly");
- }
-
- if (property.Type.IsCollection(out _))
- {
- throw new NotSupportedException(
- $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} (collection) and can't be set directly.");
- }
-
- if (!property.Type.IsNullable() && value.Type == RealmValueType.Null)
- {
- throw new ArgumentException($"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} which is not nullable, but the supplied value is .");
- }
-
- if (!property.Type.IsRealmValue() && value.Type != RealmValueType.Null && property.Type.ToRealmValueType() != value.Type)
- {
- throw new ArgumentException($"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} but the supplied value is {value.AsAny()?.GetType().Name} ({value}).");
- }
-
- if (property.IsPrimaryKey)
- {
- _managedAccessor.SetValueUnique(propertyName, value);
- return;
- }
- }
-
- _managedAccessor.SetValue(propertyName, value);
- }
+ public abstract void Set(string propertyName, RealmValue value);
//TODO Add docs
- public bool Unset(string propertyName)
- {
- return _managedAccessor.UnsetProperty(propertyName);
- }
+ public abstract bool Unset(string propertyName);
///
/// Gets the value of a backlink property. This property must have been declared
@@ -147,20 +76,7 @@ public bool Unset(string propertyName)
/// A queryable collection containing all objects pointing to this one via the
/// property specified in .
///
- public IQueryable GetBacklinks(string propertyName)
- {
- var property = GetModelProperty(propertyName, PropertyTypeEx.IsComputed);
-
- var resultsHandle = _managedAccessor.ObjectHandle.GetBacklinks(propertyName, _managedAccessor.Metadata);
-
- var relatedMeta = _managedAccessor.Realm.Metadata[property.ObjectType!];
- if (relatedMeta.Schema.BaseType == ObjectSchema.ObjectType.EmbeddedObject)
- {
- return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
- }
-
- return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
- }
+ public abstract IQueryable GetBacklinks(string propertyName);
///
/// Gets a collection of all the objects that link to this object in the specified relationship.
@@ -171,18 +87,7 @@ public IQueryable GetBacklinks(string propertyName)
/// A queryable collection containing all objects of that link
/// to the current object via .
///
- public IQueryable GetBacklinksFromType(string fromObjectType, string fromPropertyName)
- {
- Argument.Ensure(_managedAccessor.Realm.Metadata.TryGetValue(fromObjectType, out var relatedMeta), $"Could not find schema for type {fromObjectType}", nameof(fromObjectType));
-
- var resultsHandle = _managedAccessor.ObjectHandle.GetBacklinksForType(relatedMeta.TableKey, fromPropertyName, relatedMeta);
- if (relatedMeta.Schema.BaseType == ObjectSchema.ObjectType.EmbeddedObject)
- {
- return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
- }
-
- return new RealmResults(_managedAccessor.Realm, resultsHandle, relatedMeta);
- }
+ public abstract IQueryable GetBacklinksFromType(string fromObjectType, string fromPropertyName);
///
/// Gets a property.
@@ -197,14 +102,7 @@ public IQueryable GetBacklinksFromType(string fromObjectType,
/// Casting the elements to is always valid. When the collection
/// contains objects, casting to is always valid.
///
- public IList GetList(string propertyName)
- {
- var property = GetModelProperty(propertyName, PropertyTypeEx.IsList);
-
- var result = _managedAccessor.ObjectHandle.GetList(_managedAccessor.Realm, propertyName, _managedAccessor.Metadata, property.ObjectType);
- result.IsDynamic = true;
- return result;
- }
+ public abstract IList GetList(string propertyName);
///
/// Gets a property.
@@ -219,14 +117,7 @@ public IList GetList(string propertyName)
/// Casting the elements to is always valid. When the collection
/// contains objects, casting to is always valid.
///
- public ISet GetSet(string propertyName)
- {
- var property = GetModelProperty(propertyName, PropertyTypeEx.IsSet);
-
- var result = _managedAccessor.ObjectHandle.GetSet(_managedAccessor.Realm, propertyName, _managedAccessor.Metadata, property.ObjectType);
- result.IsDynamic = true;
- return result;
- }
+ public abstract ISet GetSet(string propertyName);
///
/// Gets a property.
@@ -241,67 +132,6 @@ public ISet GetSet(string propertyName)
/// Casting the values to is always valid. When the collection
/// contains objects, casting to is always valid.
///
- public IDictionary GetDictionary(string propertyName)
- {
- var property = GetModelProperty(propertyName, PropertyTypeEx.IsDictionary);
-
- var result = _managedAccessor.ObjectHandle.GetDictionary(_managedAccessor.Realm, propertyName, _managedAccessor.Metadata, property.ObjectType);
- result.IsDynamic = true;
- return result;
- }
-
- private void CheckGetPropertySuitability(string propertyName)
- {
- if (GetModelProperty(propertyName, throwOnMissing: !_isRelaxedSchema) is Property property)
- {
- if (property.Type.IsComputed())
- {
- throw new NotSupportedException(
- $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} (backlinks collection) and can't be accessed using {nameof(Dynamic)}.{nameof(Get)}. Use {nameof(GetBacklinks)} instead.");
- }
-
- if (property.Type.IsCollection(out var collectionType) && collectionType == PropertyType.Set)
- {
- throw new NotSupportedException(
- $"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} and can't be accessed using {nameof(Dynamic)}.{nameof(Get)}. Use GetSet instead.");
- }
- }
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private Property? GetModelProperty(string propertyName, bool throwOnMissing)
- {
- Argument.NotNull(propertyName, nameof(propertyName));
-
- if (!_managedAccessor.ObjectSchema.TryFindModelProperty(propertyName, out var property))
- {
- if (throwOnMissing)
- {
- throw new MissingMemberException(_managedAccessor.ObjectSchema.Name, propertyName);
- }
-
- return null;
- }
-
- return property;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private Property GetModelProperty(string propertyName, Func typeCheck, [CallerMemberName] string methodName = "")
- {
- Argument.NotNull(propertyName, nameof(propertyName));
-
- if (!_managedAccessor.ObjectSchema.TryFindModelProperty(propertyName, out var property))
- {
- throw new MissingMemberException(_managedAccessor.ObjectSchema.Name, propertyName);
- }
-
- if (!typeCheck(property.Type))
- {
- throw new ArgumentException($"{_managedAccessor.ObjectSchema.Name}.{propertyName} is {property.GetDotnetTypeName()} which can't be accessed using {methodName}.");
- }
-
- return property;
- }
+ public abstract IDictionary GetDictionary(string propertyName);
}
}
diff --git a/Realm/Realm/Dynamic/DynamicUnmanagedObjectApi.cs b/Realm/Realm/Dynamic/DynamicUnmanagedObjectApi.cs
new file mode 100644
index 0000000000..951469f78e
--- /dev/null
+++ b/Realm/Realm/Dynamic/DynamicUnmanagedObjectApi.cs
@@ -0,0 +1,97 @@
+////////////////////////////////////////////////////////////////////////////
+//
+// Copyright 2024 Realm Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License")
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+////////////////////////////////////////////////////////////////////////////
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Realms.Dynamic
+{
+ public class DynamicUnmanagedObjectApi : DynamicObjectApi
+ {
+ private readonly UnmanagedAccessor _unmanagedAccessor;
+
+ public DynamicUnmanagedObjectApi(UnmanagedAccessor unmanagedAccessor)
+ {
+ _unmanagedAccessor = unmanagedAccessor;
+ }
+
+ ///
+ public override RealmValue Get(string propertyName)
+ {
+ return _unmanagedAccessor.GetValue(propertyName);
+ }
+
+ ///
+ public override T Get(string propertyName)
+ {
+ return _unmanagedAccessor.GetValue(propertyName).As();
+ }
+
+ ///
+ public override bool TryGet(string propertyName, out RealmValue propertyValue)
+ {
+ return _unmanagedAccessor.TryGet(propertyName, out propertyValue);
+ }
+
+ ///
+ public override bool TryGet(string propertyName, out T? propertyValue) where T : default
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public override IList GetList(string propertyName)
+ {
+ return _unmanagedAccessor.GetListValue(propertyName);
+ }
+
+ ///
+ public override IDictionary GetDictionary(string propertyName)
+ {
+ return _unmanagedAccessor.GetDictionaryValue(propertyName);
+ }
+
+ ///
+ public override ISet GetSet(string propertyName)
+ {
+ return _unmanagedAccessor.GetSetValue(propertyName);
+ }
+
+ ///
+ public override void Set(string propertyName, RealmValue value)
+ {
+ _unmanagedAccessor.SetValue(propertyName, value);
+ }
+
+ ///
+ public override bool Unset(string propertyName)
+ {
+ return _unmanagedAccessor.Unset(propertyName);
+ }
+
+ ///
+ public override IQueryable GetBacklinks(string propertyName) =>
+ throw new NotSupportedException("Using the GetBacklinks is only possible for managed (persisted) objects.");
+
+ ///
+ public override IQueryable GetBacklinksFromType(string fromObjectType, string fromPropertyName) =>
+ throw new NotSupportedException("Using the GetBacklinks is only possible for managed (persisted) objects.");
+ }
+}
diff --git a/Tests/Realm.Tests/Database/RelaxedSchemaTests.cs b/Tests/Realm.Tests/Database/RelaxedSchemaTests.cs
index 43f64159b9..bebe78a4e8 100644
--- a/Tests/Realm.Tests/Database/RelaxedSchemaTests.cs
+++ b/Tests/Realm.Tests/Database/RelaxedSchemaTests.cs
@@ -340,6 +340,8 @@ public void ObjectSchema_TryFindProperty_ReturnsExtraProperties()
* - move unmanaged object to managed with extra properties and relaxed schema on (should copy properties)
* - move unmanaged object to managed with extra properties and relaxed schema off (should throw)
* - tests for unmanaged object dynamic api
+ *
+ * - serialization/deserialization
*/