forked from enlightenment/efl
csharp: Add helpers to get/set Values from Objects
Summary: The user can construct an `Eina.Value` from a plain C# `object`, using reflection to get the correct type of object and construct the correct underlying C value. Also added the `Unwrap()` method to return a C# object representing the wrapped value. Both operations are useful when using `Eina.Value` to Get/Set values from `PropertyInfo` targets as in ``` var v = new Eina.Value(propInfo.GetValue(sourceObj)); ... propInfo.SetValue(targetObj, v.Unwrap()); ``` Currently, containers are not supported. It will be added in a following commit. Depends on D9270 Reviewers: felipealmeida, vitor.sousa, segfaultxavi Reviewed By: vitor.sousa Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9272
This commit is contained in:
parent
a19bb21edf
commit
6be38caeae
|
@ -916,7 +916,86 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
private Value()
|
||||
{
|
||||
this.Handle = Alloc();
|
||||
|
||||
if (this.Handle == IntPtr.Zero)
|
||||
{
|
||||
throw new OutOfMemoryException("Failed to allocate memory for Eina.Value");
|
||||
}
|
||||
|
||||
this.Ownership = Ownership.Managed;
|
||||
MemoryNative.Memset(this.Handle, 0, eina_value_sizeof());
|
||||
}
|
||||
|
||||
/// <summary>Creates a new Value from the given C# value.</summary>
|
||||
/// <param name="obj">The object to be wrapped.</param>
|
||||
public Value(object obj) : this()
|
||||
{
|
||||
var objType = obj.GetType();
|
||||
|
||||
if (objType == typeof(sbyte))
|
||||
{
|
||||
Setup(ValueType.SByte);
|
||||
Set((sbyte)obj);
|
||||
}
|
||||
else if (objType == typeof(byte))
|
||||
{
|
||||
Setup(ValueType.Byte);
|
||||
Set((byte)obj);
|
||||
}
|
||||
else if (objType == typeof(short))
|
||||
{
|
||||
Setup(ValueType.Short);
|
||||
Set((short)obj);
|
||||
}
|
||||
else if (objType == typeof(ushort))
|
||||
{
|
||||
Setup(ValueType.UShort);
|
||||
Set((ushort)obj);
|
||||
}
|
||||
else if (objType == typeof(int))
|
||||
{
|
||||
Setup(ValueType.Int32);
|
||||
Set((int)obj);
|
||||
}
|
||||
else if (objType == typeof(uint))
|
||||
{
|
||||
Setup(ValueType.UInt32);
|
||||
Set((uint)obj);
|
||||
}
|
||||
else if (objType == typeof(long))
|
||||
{
|
||||
Setup(ValueType.Int64);
|
||||
Set((long)obj);
|
||||
}
|
||||
else if (objType == typeof(ulong))
|
||||
{
|
||||
Setup(ValueType.UInt64);
|
||||
Set((ulong)obj);
|
||||
}
|
||||
else if (objType == typeof(float))
|
||||
{
|
||||
Setup(ValueType.Float);
|
||||
Set((float)obj);
|
||||
}
|
||||
else if (objType == typeof(double))
|
||||
{
|
||||
Setup(ValueType.Double);
|
||||
Set((double)obj);
|
||||
}
|
||||
else if (objType == typeof(string))
|
||||
{
|
||||
Setup(ValueType.String);
|
||||
Set(obj as string);
|
||||
}
|
||||
else if (typeof(Efl.Object).IsAssignableFrom(objType))
|
||||
{
|
||||
Setup(ValueType.Object);
|
||||
Set(obj as Efl.Object);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Unsupported type for direct construction: {objType}");
|
||||
}
|
||||
}
|
||||
|
||||
public Value(IntPtr handle, Ownership ownership = Ownership.Managed)
|
||||
|
@ -1390,6 +1469,95 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
return b;
|
||||
}
|
||||
|
||||
/// <summary>Unwrap the value into its underlying C# value.
|
||||
///
|
||||
/// <para>Useful for methods like <see crev="PropertyInfo.SetValue(object, object)" />
|
||||
/// as it will unpack the value to it correct C# type.</para>
|
||||
/// </summary>
|
||||
/// <returns>The C# value wrapped by this value.</returns>
|
||||
public object Unwrap()
|
||||
{
|
||||
switch (GetValueType())
|
||||
{
|
||||
case ValueType.SByte:
|
||||
{
|
||||
sbyte o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.Byte:
|
||||
{
|
||||
byte o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.Short:
|
||||
{
|
||||
short o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.UShort:
|
||||
{
|
||||
ushort o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.Int32:
|
||||
{
|
||||
int o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.UInt32:
|
||||
{
|
||||
uint o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.Int64:
|
||||
case ValueType.Long:
|
||||
{
|
||||
long o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.UInt64:
|
||||
case ValueType.ULong:
|
||||
{
|
||||
ulong o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.Float:
|
||||
{
|
||||
float o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.Double:
|
||||
{
|
||||
double o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.String:
|
||||
{
|
||||
string o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
case ValueType.Object:
|
||||
{
|
||||
Efl.Object o;
|
||||
Get(out o);
|
||||
return o;
|
||||
}
|
||||
default:
|
||||
throw new InvalidOperationException($"Unsupported value type to unwrap: {GetValueType()}");
|
||||
}
|
||||
}
|
||||
|
||||
// Efl.Object conversions are made explicit to avoid ambiguity between
|
||||
// Set(Efl.Object) and Set(Value) when dealing with classes derived from
|
||||
// Efl.Object.
|
||||
|
@ -1828,7 +1996,7 @@ public class Value : IDisposable, IComparable<Value>, IEquatable<Value>
|
|||
if (!GetValueType().IsString())
|
||||
{
|
||||
throw (new ArgumentException(
|
||||
"Trying to set non-string value on a string Eina.Value"));
|
||||
"Trying to set string value on a non-string Eina.Value"));
|
||||
}
|
||||
|
||||
// No need to worry about ownership as eina_value_set will copy the passed string.
|
||||
|
|
|
@ -1029,5 +1029,76 @@ public static class TestEinaValue {
|
|||
/* Test.Assert(false, "Implement me."); */
|
||||
/* } */
|
||||
}
|
||||
|
||||
public static class TestValueFromObject
|
||||
{
|
||||
|
||||
private class Holder
|
||||
{
|
||||
public int Number { get; set; }
|
||||
public double Factor { get; set; }
|
||||
public string Name { get; set; }
|
||||
public Efl.Object Obj { get; set; }
|
||||
}
|
||||
|
||||
public static void TestConversionFromToObject()
|
||||
{
|
||||
var source = new Holder {
|
||||
Number = 1984,
|
||||
Factor = 3.14,
|
||||
Name = "Orwell",
|
||||
Obj = new Dummy.TestObject(),
|
||||
};
|
||||
|
||||
{
|
||||
var prop = source.GetType().GetProperty("Name");
|
||||
var v = new Eina.Value(prop.GetValue(source));
|
||||
|
||||
Test.AssertEquals(v.GetValueType(), Eina.ValueType.String);
|
||||
Test.AssertEquals((string)v, prop.GetValue(source));
|
||||
|
||||
Test.Assert(v.Set("New value"));
|
||||
prop.SetValue(source, v.Unwrap());
|
||||
Test.AssertEquals(prop.GetValue(source), "New value");
|
||||
}
|
||||
|
||||
{
|
||||
var prop = source.GetType().GetProperty("Factor");
|
||||
var v = new Eina.Value(prop.GetValue(source));
|
||||
|
||||
Test.AssertEquals(v.GetValueType(), Eina.ValueType.Double);
|
||||
Test.AssertAlmostEquals((double)v, (double)prop.GetValue(source));
|
||||
|
||||
Test.Assert(v.Set(2.78));
|
||||
prop.SetValue(source, v.Unwrap());
|
||||
Test.AssertEquals(prop.GetValue(source), 2.78);
|
||||
}
|
||||
|
||||
{
|
||||
var prop = source.GetType().GetProperty("Number");
|
||||
var v = new Eina.Value(prop.GetValue(source));
|
||||
|
||||
Test.AssertEquals(v.GetValueType(), Eina.ValueType.Int32);
|
||||
Test.AssertEquals((int)v, prop.GetValue(source));
|
||||
|
||||
Test.Assert(v.Set(2012));
|
||||
prop.SetValue(source, v.Unwrap());
|
||||
Test.AssertEquals(prop.GetValue(source), 2012);
|
||||
}
|
||||
|
||||
{
|
||||
var prop = source.GetType().GetProperty("Obj");
|
||||
var v = new Eina.Value(prop.GetValue(source));
|
||||
|
||||
Test.AssertEquals(v.GetValueType(), Eina.ValueType.Object);
|
||||
Test.AssertEquals((Efl.Object)v, prop.GetValue(source));
|
||||
|
||||
var newObj = new Dummy.TestObject();
|
||||
Test.Assert(v.Set(newObj));
|
||||
prop.SetValue(source, v.Unwrap());
|
||||
Test.AssertEquals(prop.GetValue(source), newObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
#pragma warning restore 1591
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue