2017-09-08 5 views
2

저는 .NET 일반 사전 <>을 가지고 Jint에서 실행중인 JavaScript 함수에 전달하려고합니다.Jint에서 Dictionary <>를 열거하는 방법

Jint는 .NET 사전을 사전처럼 취급 할 수있는 JavaScript 개체처럼 취급하지 않습니다. 개체의 .NET 속성과 메서드에는 액세스 할 수 있지만 Extension 메서드에는 액세스 할 수 없습니다.

그래서 Dictionary 키를 계산할 수는 있지만이를 열거하거나 ToArray()를 호출 할 수는 없습니다.

사전 중 값을 읽으려면 dict [key]를 사용할 수 있지만이 경우 사전에 키를 알 수 없습니다.

키를 열거하거나 .NET 일반 사전의 모든 항목을 가져 오는 방법은 무엇입니까?

JavaScript에 전달하기 전에 사전에 뭔가를하거나 변환하는 것에 익숙합니다. 키 배열을 별도로 전달하지 않아도됩니다. 이것은 다른 데이터 구조 안에 있으며 각 사전에 대해 그렇게하는 것이 더 복잡해 지지만 다른 솔루션을 찾을 수없는 경우 고려중인 옵션 중 하나입니다.

나는 역학을 사용하지 않기를 원합니다. 나는 과거에 무겁게 사용되었을 때 기억을 새기고있는 데 어려움을 겪었다.

+0

이전에 [tag : jint]를 사용한 적이 없지만 귀하의 질문이 자바 스크립트에서 개체의 멤버를 열거하는 방법 인 것 같습니다. javascript *의 객체는 * 사전이며 일반적으로 그렇게 직렬화됩니다. [This] (https://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object) 질문에 대한 답변을 얻으실 수 있습니다 – Rob

+0

다음과 같은 javascript 객체 속성을 반복 할 수 있습니다. [this] (https://stackoverflow.com/questions/85992/how-do-i-enumerate-the-properties-of-a-javascript-object), 그러나 당신이 원하는 것을 정확하게 말하기는 어렵습니다. 여기서 해. .net 측에서는'Dictionary 'KeyCollection을 열거하고 모든 키 목록을 얻을 수 있습니다. –

+0

은 jint에서 작동하지 않습니다. 그것은 자바 스크립트에서 객체를 선언 한 것입니다. 일반적인 js 방식을 사용할 수 있지만,NET 개체가 js 환경으로 전달되고 일반 js 개체처럼 처리 할 수 ​​없습니다. 나는 이미 특별히 (var i in mydict)와 (var i in mydict.Keys) 어느 쪽도 노력하지 않았다. – Zack

답변

2

난 그냥 같은 문제로 실행하고 사전에 열거를 사용하여 그것을 해결 :

// 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는 일반 인덱서를 제대로 처리 할 수 ​​없으며 throw합니다. System.InvalidOperationException : 일치하는 인덱서가 없습니다.

0

ToArray 방법을 해결하는 자신의 ObjectWrapper을 만들 수 있습니다. 다음은 오류 처리 등을 개선해야합니다, 그것을 내 빠른 자상하지만 그것은 시작의 : 특정 상황에 맞게 할 수

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(); 
     } 
    } 
} 
1

간단한 대안은 대신 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})"); 
     } 
    } 
} 
+0

너는 천재 야! –