From 9095cc788d7697c37e446e213aae4e04a8f01853 Mon Sep 17 00:00:00 2001 From: Florian Rappl Date: Fri, 21 May 2021 02:56:54 +0200 Subject: [PATCH] Changed types to be reflected as objects --- CHANGELOG.md | 1 + src/Mages.Core.Tests/FunctionTests.cs | 14 ++--- src/Mages.Core.Tests/OperationTests.cs | 33 ++++++++--- .../Runtime/Converters/ConverterExtensions.cs | 21 +++---- .../Runtime/Converters/TypeCategories.cs | 3 + .../Runtime/Functions/StandardFunctions.cs | 2 +- src/Mages.Core/Runtime/Helpers.cs | 6 +- src/Mages.Core/Runtime/Matrix.cs | 15 +---- src/Mages.Core/Runtime/Types/MagesBoolean.cs | 22 +++++++ src/Mages.Core/Runtime/Types/MagesCMatrix.cs | 22 +++++++ src/Mages.Core/Runtime/Types/MagesComplex.cs | 22 +++++++ src/Mages.Core/Runtime/Types/MagesFunction.cs | 21 +++++++ src/Mages.Core/Runtime/Types/MagesMatrix.cs | 22 +++++++ src/Mages.Core/Runtime/Types/MagesNumber.cs | 22 +++++++ src/Mages.Core/Runtime/Types/MagesObject.cs | 22 +++++++ src/Mages.Core/Runtime/Types/MagesString.cs | 21 +++++++ .../Runtime/Types/MagesUndefined.cs | 20 +++++++ src/Mages.Core/Runtime/WrapperObject.cs | 57 +++++-------------- .../Functions/HelpFunctions.cs | 29 +++++++--- 19 files changed, 280 insertions(+), 95 deletions(-) create mode 100644 src/Mages.Core/Runtime/Types/MagesBoolean.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesCMatrix.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesComplex.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesFunction.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesMatrix.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesNumber.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesObject.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesString.cs create mode 100644 src/Mages.Core/Runtime/Types/MagesUndefined.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e553fff..de0b537e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - Changed the range operator from `:` to `..` (#76) - Changed library target to .NET Standard 2 (#68) - Changed application to run on .NET Core 3.1 (#68) +- Changed types to be reflected as objects (#60) # 1.6.1 diff --git a/src/Mages.Core.Tests/FunctionTests.cs b/src/Mages.Core.Tests/FunctionTests.cs index 10c62b27..fe3a3258 100644 --- a/src/Mages.Core.Tests/FunctionTests.cs +++ b/src/Mages.Core.Tests/FunctionTests.cs @@ -326,49 +326,49 @@ public void ListWithOneEntryAddNewEntryWithIndexSetAccessor() [Test] public void TypeOfNothingIsUndefined() { - var result = "type(null)".Eval(); + var result = "type(null).name".Eval(); Assert.AreEqual("Undefined", result); } [Test] public void TypeOfMatrixIsMatrix() { - var result = "type([])".Eval(); + var result = "type([]).name".Eval(); Assert.AreEqual("Matrix", result); } [Test] public void TypeOfDictionaryIsObject() { - var result = "type(new {})".Eval(); + var result = "type(new {}).name".Eval(); Assert.AreEqual("Object", result); } [Test] public void TypeOfStringIsString() { - var result = "type(\"\")".Eval(); + var result = "type(\"\").name".Eval(); Assert.AreEqual("String", result); } [Test] public void TypeOfBooleanIsBoolean() { - var result = "type(true)".Eval(); + var result = "type(true).name".Eval(); Assert.AreEqual("Boolean", result); } [Test] public void TypeOfDoubleIsNumber() { - var result = "type(2.3)".Eval(); + var result = "type(2.3).name".Eval(); Assert.AreEqual("Number", result); } [Test] public void TypeOfDelegateIsFunction() { - var result = "type(() => {})".Eval(); + var result = "type(() => {}).name".Eval(); Assert.AreEqual("Function", result); } diff --git a/src/Mages.Core.Tests/OperationTests.cs b/src/Mages.Core.Tests/OperationTests.cs index b3f91ad2..3f543bd0 100644 --- a/src/Mages.Core.Tests/OperationTests.cs +++ b/src/Mages.Core.Tests/OperationTests.cs @@ -795,21 +795,28 @@ public void SomethingAintNothingIsFalse() [Test] public void TypeOperatorOnNullYieldsUndefined() { - var result = "&null".Eval(); + var result = "(&null).name".Eval(); Assert.AreEqual("Undefined", result); } [Test] - public void TypeOperatorOnResultOfTypeOperatorYieldsString() + public void TypeOperatorOnResultOfTypeOperatorYieldsObject() { - var result = "& &null".Eval(); + var result = "(& &null).name".Eval(); + Assert.AreEqual("Object", result); + } + + [Test] + public void TypeOperatorOnResultOfTypeOperatorNameYieldsString() + { + var result = "(& (&null).name).name".Eval(); Assert.AreEqual("String", result); } [Test] public void TypeOperatorOnMatrixYieldsMatrix() { - var result = "&[1, 2, 3]".Eval(); + var result = "(&[1, 2, 3]).name".Eval(); Assert.AreEqual("Matrix", result); } @@ -839,7 +846,7 @@ public void PipeOperatorAfterMinusOnCurriedMultiplyYieldsResult() [Test] public void PipeOperatorIsLowerPrecendenceThanEquals() { - var result = "3 == 4 | type".Eval(); + var result = "(3 == 4 | type).name".Eval(); Assert.IsInstanceOf(result); Assert.AreEqual("Boolean", result); } @@ -847,7 +854,7 @@ public void PipeOperatorIsLowerPrecendenceThanEquals() [Test] public void PipeOperatorIsLowerPrecendenceThanOr() { - var result = "1 || 0 | type".Eval(); + var result = "(1 || 0 | type).name".Eval(); Assert.IsInstanceOf(result); Assert.AreEqual("Boolean", result); } @@ -855,19 +862,27 @@ public void PipeOperatorIsLowerPrecendenceThanOr() [Test] public void PipeOperatorOnTypeYieldsResult() { - var result = "2 | type".Eval(); + var result = "(2 | type).name".Eval(); Assert.IsInstanceOf(result); Assert.AreEqual("Number", result); } [Test] - public void PipeOperatorOnTypeOfTypeYieldsString() + public void PipeOperatorOnTypeOfTypeNameYieldsString() { - var result = "2 | type | type".Eval(); + var result = "((2 | type).name | type).name".Eval(); Assert.IsInstanceOf(result); Assert.AreEqual("String", result); } + [Test] + public void PipeOperatorOnTypeOfTypeYieldsObject() + { + var result = "(2 | type | type).name".Eval(); + Assert.IsInstanceOf(result); + Assert.AreEqual("Object", result); + } + [Test] public void InvalidAssignmentAddWithNumberYieldsError() { diff --git a/src/Mages.Core/Runtime/Converters/ConverterExtensions.cs b/src/Mages.Core/Runtime/Converters/ConverterExtensions.cs index 1422d7e0..f14f3b52 100644 --- a/src/Mages.Core/Runtime/Converters/ConverterExtensions.cs +++ b/src/Mages.Core/Runtime/Converters/ConverterExtensions.cs @@ -1,5 +1,6 @@ namespace Mages.Core.Runtime.Converters { + using Mages.Core.Runtime.Types; using System; using System.Collections.Generic; using System.Globalization; @@ -16,17 +17,17 @@ public static class ConverterExtensions /// /// The value to get the type of. /// The MAGES type string. - public static String ToType(this Object value) => value switch + public static IDictionary ToType(this Object value) => value switch { - Double _ => "Number", - Complex _ => "Complex", - String _ => "String", - Boolean _ => "Boolean", - Double[,] _ => "Matrix", - Complex[,] _ => "CMatrix", - Function _ => "Function", - IDictionary _ => "Object", - _ => "Undefined", + Double _ => MagesNumber.Type, + Complex _ => MagesComplex.Type, + String _ => MagesString.Type, + Boolean _ => MagesBoolean.Type, + Double[,] _ => MagesMatrix.Type, + Complex[,] _ => MagesCMatrix.Type, + Function _ => MagesFunction.Type, + IDictionary _ => MagesObject.Type, + _ => MagesUndefined.Type, }; /// diff --git a/src/Mages.Core/Runtime/Converters/TypeCategories.cs b/src/Mages.Core/Runtime/Converters/TypeCategories.cs index d31de892..9b4e561d 100644 --- a/src/Mages.Core/Runtime/Converters/TypeCategories.cs +++ b/src/Mages.Core/Runtime/Converters/TypeCategories.cs @@ -2,15 +2,18 @@ { using System; using System.Collections.Generic; + using System.Numerics; static class TypeCategories { public static readonly Dictionary> Mapping = new Dictionary> { { typeof(Double), new List { typeof(Double), typeof(Single), typeof(Decimal), typeof(Byte), typeof(UInt16), typeof(UInt32), typeof(UInt64), typeof(Int16), typeof(Int32), typeof(Int64) } }, + { typeof(Complex), new List { typeof(Complex) } }, { typeof(Boolean), new List { typeof(Boolean) } }, { typeof(String), new List { typeof(String), typeof(Char) } }, { typeof(Double[,]), new List { typeof(Double[,]), typeof(Double[]), typeof(List) } }, + { typeof(Complex[,]), new List { typeof(Complex[,]), typeof(Complex[]), typeof(List) } }, { typeof(Function), new List { typeof(Function), typeof(Delegate) } }, { typeof(IDictionary), new List { typeof(IDictionary), typeof(Object) } } }; diff --git a/src/Mages.Core/Runtime/Functions/StandardFunctions.cs b/src/Mages.Core/Runtime/Functions/StandardFunctions.cs index 598270ba..0019d0fa 100644 --- a/src/Mages.Core/Runtime/Functions/StandardFunctions.cs +++ b/src/Mages.Core/Runtime/Functions/StandardFunctions.cs @@ -866,7 +866,7 @@ public static class StandardFunctions public static readonly Function Is = new Function(args => { return Curry.MinTwo(Is, args) ?? - If.Is(args, type => type == args[1].ToType()) ?? + If.Is(args, type => type == args[1].ToType()["name"].ToString()) ?? If.Is>(args, type => type.Satisfies(args[1])); }); diff --git a/src/Mages.Core/Runtime/Helpers.cs b/src/Mages.Core/Runtime/Helpers.cs index 626e154b..a574568e 100644 --- a/src/Mages.Core/Runtime/Helpers.cs +++ b/src/Mages.Core/Runtime/Helpers.cs @@ -124,14 +124,12 @@ public static Boolean Satisfies(this IDictionary constraints, Ob { foreach (var constraint in constraints) { - var val = default(Object); - - if (obj.TryGetValue(constraint.Key, out val)) + if (obj.TryGetValue(constraint.Key, out var val)) { var simple = constraint.Value as String; var extended = constraint.Value as IDictionary; - if ((simple == null || val.ToType() == simple) && + if ((simple == null || val.ToType()["name"].ToString() == simple) && (extended == null || extended.Satisfies(val))) { continue; diff --git a/src/Mages.Core/Runtime/Matrix.cs b/src/Mages.Core/Runtime/Matrix.cs index 1d49997c..0a55b69c 100644 --- a/src/Mages.Core/Runtime/Matrix.cs +++ b/src/Mages.Core/Runtime/Matrix.cs @@ -7,20 +7,11 @@ static class Matrix { - public static Int32 GetRows(this T[,] matrix) - { - return matrix.GetLength(0); - } + public static Int32 GetRows(this T[,] matrix) => matrix.GetLength(0); - public static Int32 GetColumns(this T[,] matrix) - { - return matrix.GetLength(1); - } + public static Int32 GetColumns(this T[,] matrix) => matrix.GetLength(1); - public static Int32 GetCount(this T[,] matrix) - { - return matrix.GetLength(0) * matrix.GetLength(1); - } + public static Int32 GetCount(this T[,] matrix) => matrix.GetLength(0) * matrix.GetLength(1); public static Object GetKeys(this T[,] matrix) { diff --git a/src/Mages.Core/Runtime/Types/MagesBoolean.cs b/src/Mages.Core/Runtime/Types/MagesBoolean.cs new file mode 100644 index 00000000..39483279 --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesBoolean.cs @@ -0,0 +1,22 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Converters; + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesBoolean + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + args[0].ToBoolean(); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "Boolean" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesCMatrix.cs b/src/Mages.Core/Runtime/Types/MagesCMatrix.cs new file mode 100644 index 00000000..aec41e0f --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesCMatrix.cs @@ -0,0 +1,22 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Converters; + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesCMatrix + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + args[0].ToComplex().ToMatrix(); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "CMatrix" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesComplex.cs b/src/Mages.Core/Runtime/Types/MagesComplex.cs new file mode 100644 index 00000000..08e06b69 --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesComplex.cs @@ -0,0 +1,22 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Converters; + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesComplex + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + args[0].ToComplex(); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "Complex" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesFunction.cs b/src/Mages.Core/Runtime/Types/MagesFunction.cs new file mode 100644 index 00000000..98efa68d --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesFunction.cs @@ -0,0 +1,21 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesFunction + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + (args[0] as Function); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "Function" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesMatrix.cs b/src/Mages.Core/Runtime/Types/MagesMatrix.cs new file mode 100644 index 00000000..13f4f9ab --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesMatrix.cs @@ -0,0 +1,22 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Converters; + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesMatrix + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + args[0].ToNumber().ToMatrix(); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "Matrix" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesNumber.cs b/src/Mages.Core/Runtime/Types/MagesNumber.cs new file mode 100644 index 00000000..c367cbf2 --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesNumber.cs @@ -0,0 +1,22 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Converters; + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesNumber + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + args[0].ToNumber(); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "Number" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesObject.cs b/src/Mages.Core/Runtime/Types/MagesObject.cs new file mode 100644 index 00000000..53d8895d --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesObject.cs @@ -0,0 +1,22 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Converters; + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesObject + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + args[0].ToObject(); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "Object" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesString.cs b/src/Mages.Core/Runtime/Types/MagesString.cs new file mode 100644 index 00000000..da0b251a --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesString.cs @@ -0,0 +1,21 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesString + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? + Stringify.This(args[0]); + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "String" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/Types/MagesUndefined.cs b/src/Mages.Core/Runtime/Types/MagesUndefined.cs new file mode 100644 index 00000000..ab029256 --- /dev/null +++ b/src/Mages.Core/Runtime/Types/MagesUndefined.cs @@ -0,0 +1,20 @@ +namespace Mages.Core.Runtime.Types +{ + using Mages.Core.Runtime.Functions; + using System; + using System.Collections.Generic; + + static class MagesUndefined + { + private static readonly Function Create = new Function(args => + { + return Curry.MinOne(Create, args) ?? null; + }); + + public static readonly IDictionary Type = new Dictionary + { + { "name", "Undefined" }, + { "create", Create }, + }; + } +} diff --git a/src/Mages.Core/Runtime/WrapperObject.cs b/src/Mages.Core/Runtime/WrapperObject.cs index a8f2a236..71563ef4 100644 --- a/src/Mages.Core/Runtime/WrapperObject.cs +++ b/src/Mages.Core/Runtime/WrapperObject.cs @@ -96,8 +96,7 @@ public Object this[String key] { get { - var result = default(Object); - TryGetValue(key, out result); + TryGetValue(key, out var result); return result; } set { TrySetValue(key, value); } @@ -121,28 +120,19 @@ public Object this[String key] /// public ICollection Values => _extends.Values; - void ICollection>.Add(KeyValuePair item) - { - Add(item.Key, item.Value); - } + void ICollection>.Add(KeyValuePair item) => Add(item.Key, item.Value); /// /// Sets the provided value at the provided property. /// /// The name of the property. /// The value to use. - public void Add(String key, Object value) - { - TrySetValue(key, value); - } + public void Add(String key, Object value) => TrySetValue(key, value); /// /// Resets the extension object. /// - public void Clear() - { - _extends.Clear(); - } + public void Clear() => _extends.Clear(); /// /// Checks if the underlying object or the extension @@ -150,10 +140,7 @@ public void Clear() /// /// The item to check for. /// True if the key is used, otherwise false. - public Boolean Contains(KeyValuePair item) - { - return ContainsKey(item.Key); - } + public Boolean Contains(KeyValuePair item) => ContainsKey(item.Key); /// /// Checks if the underlying object or the extension @@ -161,10 +148,7 @@ public Boolean Contains(KeyValuePair item) /// /// The key to check for. /// True if the key is used, otherwise false. - public Boolean ContainsKey(String key) - { - return _proxies.ContainsKey(key) || _extends.ContainsKey(key); - } + public Boolean ContainsKey(String key) => _proxies.ContainsKey(key) || _extends.ContainsKey(key); void ICollection>.CopyTo(KeyValuePair[] array, Int32 arrayIndex) { @@ -174,25 +158,17 @@ void ICollection>.CopyTo(KeyValuePair /// The extension's enumerator. - public IEnumerator> GetEnumerator() - { - return _extends.Concat(_proxies.Select(m => new KeyValuePair(m.Key, m.Value.Value))).GetEnumerator(); - } + public IEnumerator> GetEnumerator() => + _extends.Concat(_proxies.Select(m => new KeyValuePair(m.Key, m.Value.Value))).GetEnumerator(); - Boolean ICollection>.Remove(KeyValuePair item) - { - return Remove(item.Key); - } + Boolean ICollection>.Remove(KeyValuePair item) => Remove(item.Key); /// /// Removes the item from the extension. /// /// The key of the item to be removed. /// True if it could be removed, otherwise false. - public Boolean Remove(String key) - { - return _extends.Remove(key); - } + public Boolean Remove(String key) => _extends.Remove(key); /// /// Tries to get the value from the given key. @@ -202,9 +178,7 @@ public Boolean Remove(String key) /// True if the value could be retrieved, otherwise false. public Boolean TryGetValue(String key, out Object value) { - var proxy = default(BaseProxy); - - if (_proxies.TryGetValue(key, out proxy)) + if (_proxies.TryGetValue(key, out var proxy)) { value = proxy.Value; return true; @@ -219,9 +193,7 @@ public Boolean TryGetValue(String key, out Object value) private void TrySetValue(String key, Object value) { - var proxy = default(BaseProxy); - - if (_proxies.TryGetValue(key, out proxy)) + if (_proxies.TryGetValue(key, out var proxy)) { proxy.Value = value; } @@ -231,10 +203,7 @@ private void TrySetValue(String key, Object value) } } - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); #endregion } diff --git a/src/Mages.Repl.Base/Functions/HelpFunctions.cs b/src/Mages.Repl.Base/Functions/HelpFunctions.cs index 3c80c545..75cf8068 100644 --- a/src/Mages.Repl.Base/Functions/HelpFunctions.cs +++ b/src/Mages.Repl.Base/Functions/HelpFunctions.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; + using System.Numerics; using System.Text; sealed class HelpFunctions @@ -60,8 +61,9 @@ private String Info(String topic, Object value) { var sb = new StringBuilder(); var type = value.ToType(); + var typeName = $"{type["name"]}"; sb.AppendFormat("Type of '{0}': ", topic); - sb.AppendLine(type); + sb.AppendLine(typeName); sb.Append("Number value: "); sb.Append(Stringify.This(value.ToNumber())); sb.AppendLine(); @@ -71,25 +73,36 @@ private String Info(String topic, Object value) sb.Append("String value: "); sb.Append(Stringify.This(value)); - switch (type) + switch (typeName) { case "Number": - break; + case "Complex": case "String": - break; case "Boolean": + case "Function": + case "Undefined": break; - case "Matrix": + case "CMatrix": + sb.AppendLine(); + sb.Append("Columns: "); + sb.Append(((Complex[,])value).GetLength(1)); + sb.AppendLine(); + sb.Append("Rows: "); + sb.Append(((Complex[,])value).GetLength(0)); break; - case "Function": + case "Matrix": + sb.AppendLine(); + sb.Append("Columns: "); + sb.Append(((Double[,])value).GetLength(1)); + sb.AppendLine(); + sb.Append("Rows: "); + sb.Append(((Double[,])value).GetLength(0)); break; case "Object": sb.AppendLine(); sb.Append("Keys: "); sb.Append(String.Join(", ", ((IDictionary)value).Select(m => m.Key))); break; - case "Undefined": - break; } return sb.ToString();