【问题标题】:How to Enumerate a Dictionary<> in Jint如何在 Jint 中枚举字典<>
【发布时间】:2018-02-16 23:59:57
【问题描述】:

我有一个 .NET 通用字典,我想将它传递给我在 Jint 中运行的 JavaScript 函数。

Jint 不会将 .NET Dictionary 视为 JavaScript 对象,而 JavaScript 对象可被视为字典。您可以访问对象的 .NET 属性和方法,但不能访问扩展方法。

因此,虽然我可以获得字典键的计数,但我无法枚举它或对其调用 ToArray()。

我可以使用 dict[key] 从字典中读取值,但在这种情况下我事先不知道键。

如何枚举键或获取 .NET 通用字典中的所有条目?

我愿意对字典做一些事情或在我将它传递给它之前对其进行转换,或者弄清楚如何在 JavaScript 中做它。我宁愿不必单独传递一个键数组。这是在另一个数据结构中,对每个字典都这样做会使其更加复杂,但如果我找不到其他解决方案,这是我正在考虑的选项之一。

我宁愿远离使用动态。在过去大量使用它们时,我遇到了泄漏内存的问题。

【问题讨论】:

  • 我以前从未使用过jint,但看起来你的问题是如何在javascript中枚举对象的成员。 javascript 中的对象 字典,通常是这样序列化的。 This 可能会回答您的问题
  • 您可以遍历 JavaScript 对象属性,例如 this,但是,在这里很难准确说出您想要做什么。在 .net 端,你可以枚举一个Dictionary&lt;T&gt; KeyCollection,并获取所有键的列表。
  • 在 jint 中不起作用。如果该对象是在 JavaScript 中声明的,我可以使用普通的 js 方式来做这件事,但是它是一个传递到 js 环境中的 .NET 对象,你不能像普通的 js 对象一样对待它。我已经专门尝试过 for(var i in mydict) 和 for(var i in mydict.Keys) 都不起作用。
  • Jint 不会尝试解析扩展方法,例如 ToArray。你可以尝试推出你自己的ObjectWrapper 版本,但我只是尝试过,这并不简单(一些有用的方法是私有的,所以你必须复制它们)

标签: javascript c# dictionary jint


【解决方案1】:

我刚刚遇到了同样的问题,并通过使用字典上的枚举器解决了它:

// Javascript in Jint:
var enumerator = myDictionary.GetEnumerator();
while (enumerator.MoveNext()) {
    var key = enumerator.Current.Key;
    var value = enumerator.Current.Value;
    // do stuff with key and/or value
}

如果您对两者都不感兴趣,您可以使用相同的方式迭代 myDictionary.Keys 或 myDictionary.Values。

注意:您提到您可以使用dict[key]。至少对我来说,我有一个复杂的 struct 作为键,这不起作用。显然 Jint 不能很好地处理通用索引器并抛出:System.InvalidOperationException: No matching indexer found.

【讨论】:

    【解决方案2】:

    一个可能适合您特定情况的简单替代方法是将值作为 JSON 传递。在很多情况下这很有用,尤其是在使用 jint 编写测试时。虽然这增加了对序列化程序的依赖,而且可能更慢,但非常方便,而且肯定是可预测和可调试的。

    using Jint;
    using Newtonsoft.Json;
    
    namespace Extensions
    {
        public static class EngineExtentions {
            public static void SetJsonValue(this Engine source, string name, object value)
            {
                source.SetValue(name, JsonConvert.SerializeObject(value));
                source.Execute($"{name} = JSON.parse({name})");
            }
        }
    }
    

    【讨论】:

    • 哥们,你真是个天才!
    【解决方案3】:

    您可以创建自己的ObjectWrapper,为它的目标对象解析ToArray 方法。这是我的快速尝试,您需要改进错误处理等内容,但这是一个开始:

    public class ObjectWrapperExt: ObjectInstance, IObjectWrapper
    {
        private ObjectWrapper _target;
    
        public ObjectWrapperExt(Engine engine, Object obj)
            : base(engine)
        {
            _target = new ObjectWrapper(engine, obj);
        }
        public object Target => _target.Target;
    
        public override PropertyDescriptor GetOwnProperty(string propertyName)
        {
    
            if (propertyName == "ToArray")
            {
                if (this.Properties.TryGetValue(propertyName, out var prop)) return prop;
    
                var descriptor = new PropertyDescriptor(new ToArrayFunctionInstance(Engine), false, true, false);
                Properties.Add(propertyName, descriptor);
                return descriptor;
            }
    
            return _target.GetOwnProperty(propertyName);
        }
    
        public override void Put(string propertyName, JsValue value, bool throwOnError)
        {
            _target.Put(propertyName, value, throwOnError);
        }
    
        public class ToArrayFunctionInstance : FunctionInstance
        {
            private static MethodInfo toArray = typeof(Enumerable).GetMethod("ToArray", BindingFlags.Static | BindingFlags.Public);
    
            public ToArrayFunctionInstance(Engine engine) : base(engine, null,null, false)
            {   
            }
    
            public override JsValue Call(JsValue thisObject, JsValue[] arguments)
            {
                var target = (thisObject.AsObject() is IObjectWrapper w)? w.Target : throw new NotSupportedException();
                var targetType = target.GetType();
    
                var enumImpl = targetType.GetInterfaces()
                    .Where(_ => _.IsGenericType)
                    .Where(_ => _.GetGenericTypeDefinition() == typeof(IEnumerable<>))
                    .FirstOrDefault();
    
                if(enumImpl != null)
                {
                    var arg = enumImpl.GetGenericArguments();
                    var value = toArray.MakeGenericMethod(arg).Invoke(null, new[] { target });
                    return JsValue.FromObject(Engine, value);
                }
                throw new NotSupportedException();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-31
      • 1970-01-01
      • 2010-10-15
      • 1970-01-01
      • 1970-01-01
      • 2011-05-16
      相关资源
      最近更新 更多