IUserDataContainer
IUserDataContainer is an interface for classes that can hold user-data.
/// <summary>Interface for classes that can hold user-data.</summary>
public interface IUserDataContainer
{
/// <summary>Is <see cref="UserData"/> assigned.</summary>
bool HasUserData { get; }
/// <summary>Policy whether this implementation constructs <see cref="UserData"/> lazily.</summary>
bool UserDataInitializedOnGet { get; }
/// <summary>User-data in concurrent safe map. Lazy constructed on get. If object set to read-only state, so is <see cref="UserData"/> map.</summary>
/// <remarks>Setter use is discouraged. The implementation is allowed to prevent it by throwing <see cref="InvalidOperationException"/>.</remarks>
/// <exception cref="InvalidOperationException">If modifying read-only object, or if class prohibits setting data object.</exception>
IDictionary<string, object?> UserData { get; set; }
}
UserDataContainerBase can be used as base class. This base class requires explicit dictionary assignment to .UserData.
public class MyClass0 : UserDataContainerBase { }
IUserDataContainer container = new MyClass0();
container.UserData = new ConcurrentDictionary<string, object?>();
container.UserData["Hello"] = "World";
WriteLine(container.UserData["Hello"]); // "World"
UserDataContainerBase.LazyConstructed is base class that lazy-initializes .UserData on getter.
public class MyClass1 : UserDataContainerBase.LazyConstructed { }
IUserDataContainer container = new MyClass1();
container.UserData["Hello"] = "World";
WriteLine(container.UserData["Hello"]); // "World"
.SetUserData(key, value) is an extension method that assigns a value to .UserData.
IUserDataContainer container = new MyClass1().SetUserData("Hello", "World");
WriteLine(container.UserData["Hello"]); // "World"
ReadOnlyAssignableClass.UserDataContainerLazyConstructed is base class that implements both IReadOnly and IUserDataContainer.
public class MyClass2 : ReadOnlyAssignableClass.UserDataContainerLazyConstructed { }
IUserDataContainer container = new MyClass2().SetUserData("Hello", "World").SetReadOnly();
WriteLine(container.UserData["Hello"]); // "World"
Dictionary is set to read-only state along with container.
try
{
IUserDataContainer container = new MyClass2().SetReadOnly().SetUserData("Hello", "World");
} catch (InvalidOperationException e)
{
WriteLine(e);
}
Full Example
Full example
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Avalanche.Message;
using Avalanche.Utilities;
using static System.Console;
class userdatacontainer
{
public static void Run()
{
{
// <00>
IUserDataContainer container = new MyClass0();
container.UserData = new ConcurrentDictionary<string, object?>();
container.UserData["Hello"] = "World";
WriteLine(container.UserData["Hello"]); // "World"
// </00>
}
{
// <01>
IUserDataContainer container = new MyClass1();
container.UserData["Hello"] = "World";
WriteLine(container.UserData["Hello"]); // "World"
// </01>
}
{
// <02>
IUserDataContainer container = new MyClass1().SetUserData("Hello", "World");
WriteLine(container.UserData["Hello"]); // "World"
// </02>
}
{
// <03>
IUserDataContainer container = new MyClass2().SetUserData("Hello", "World").SetReadOnly();
WriteLine(container.UserData["Hello"]); // "World"
// </03>
}
{
// <04>
MyClass2 container = new MyClass2();
IDictionary<string, object?> data = container.UserData;
container.SetReadOnly();
try
{
data["Hello"] = "World";
} catch (InvalidOperationException e)
{
WriteLine(e);
}
// </04>
}
{
// <05>
try
{
IUserDataContainer container = new MyClass2().SetReadOnly().SetUserData("Hello", "World");
} catch (InvalidOperationException e)
{
WriteLine(e);
}
// </05>
}
}
// <100>
public class MyClass0 : UserDataContainerBase { }
// </100>
// <101>
public class MyClass1 : UserDataContainerBase.LazyConstructed { }
// </101>
// <102>
public class MyClass2 : ReadOnlyAssignableClass.UserDataContainerLazyConstructed { }
// </102>
}