2010-12-21 3 views
0

Perl의 Autovivification에서 머리를 감싸고 소리가 나는 것을 기반으로 C#에서 동적 객체가 런타임까지 유형이 할당되지 않았거나 완전히 벗어 났으므로 작동하는 것처럼 보입니다. 그렇다면 거기에 내가 C에서 다리를 놓을 수있는 비교할 수있는 아이디어가있다 #은 이해가 되니?

편집
좋아요, 그래서 나는 분명히 벗어났습니다. 그래서 2 부분 질문의 두 번째 부분으로 C#에서 개념적으로 비교 가능한 것이 있습니까? 명확하게하려면 C#에서 Autovivification과 비슷한 개념을 찾고 있습니다. 정확하게 동일 할 필요는 없지만 개념적으로는 충분히 이해가 가능합니다. 그리고 내가 eariller를 언급했듯이 나는 결코 상상의 모든 스트레칭으로 펄 해커 또는 파이썬 해커가 아니지만 나는 C 언어 C, C++, C#, 자바, 자바 스크립트에 익숙하다. 나는 C#의 역 동성을 생각하고 있었지만 지금 당장은 게으른 로딩이 도움이된다면 여기에 정보를 기반으로 생각하고 있습니다 ....C에서의 자동 가상화 #

+3

. http://en.wikipedia.org/wiki/Autovivification을 참조하십시오 – mob

+0

예, 거기에 있었지만 저는 Perl의 좀 더 복잡한 부분에 유창하지는 않습니다. 그래서 파이썬에서는 덜합니다. – Terrance

+0

+1은 완전히 벗어났습니다. 롤. 어딘가에서 시작해야 해 ... – Terrance

답변

9

C#은 말할 수 없지만, 평범한 용어로 볼 때 Perl의 자동 가상화는 필요에 따라 정의되지 않은 값으로 컨테이너 객체를 만드는 과정입니다.

대부분의 Perl은 매우 동적 임에도 불구하고 Perl의 참조 해제 구문은 컴파일시 참조 유형을 명확하게 지정합니다. 이를 통해 인터프리터는 변수가 정의되기 전에 변수에서 필요한 것을 알 수 있습니다.

my $var; # undefined 

# to autovivify to an array: 
@$var = 1..5; # @ here implies ARRAY 
$$var[4] = 5; # square brackets imply ARRAY 
$#$var;  # $# implies ARRAY (returns the last index number) 

# to autovivify to a hash: 

%$var = (a => 1); # % implies HASH 
$$var{asdf} = 5; # curly braces imply HASH 

이 목록은 더 길 수도 있지만 생각해 봐야합니다.그래서 기본적으로

,이 같은 라인이있을 때 :

my $var; 
$var->[1]{x}[3]{asdf} 

펄이 ->의 오른쪽에 보이는 대괄호를 본다. 즉, 호출자 $var은 배열 참조 여야합니다. invocant가 정의되지 않았으므로 Perl은 새로운 배열을 만들고 그 참조를 $var에 설치합니다. 이후의 모든 역 참조 해제에 대해 동일한 프로세스가 반복됩니다.

그래서 위의 선은 정말 의미 따라서 autovivification 매우 끔찍한이며,

 
    (((($var //= [])->[1] //= {})->{x} //= [])->[3] //= {})->{asdf}; 

합니다. 당신은 필요

CJM의 의견에 따라 경찰, 다른 언어로 autovivification을 달성하기 위해, 일반적으로 비 펄 용어로 이것을 넣어 :

가 업데이트 (//=는 5.10+ 펄의 정의 또는 대입 연산자입니다) [...]{...}을 통해 인덱싱을 지원하는 지연 객체입니다. 이러한 인덱싱 작업 중 하나를 수행하면 개체가 배열이나 해시로 바뀝니다. 객체가 액세스 될 때마다 셀이 비어 있으면 다른 게으른 객체를 반환해야합니다.

obj = new lazy_obj() 

level1 = obj[4] # sets obj to be an array, returns a new lazy_obj for level1 

level2 = level1{asdf} # sets level1 (and obj[4]) to a hash, 
         # returns a new lazy_obj for level2 

그래서 기본적으로는 모두 배열과 해시 첨자 (또는 동급)과 인덱싱을 지원하는 객체를 생성 할 수있는 능력, 그리고 객체가 다른 객체와 메모리에 자신을 대체 할 수 있도록하는 메커니즘을 두 가지가 필요합니다 (또는 하나 개의 해석에 자신을 고정하고 내부적으로 새로운 객체를 저장할 수있는 다음의 의사 코드와 같은

뭔가를 시작 될 수있다 :.

class autoviv { 
    private var content; 

    method array_subscript (idx) { 
     if (!content) { 
      content = new Array(); 
     } 
     if (typeof content == Array) { 
      if (exists content[idx]) return content[idx]; 
      return content[idx] = new autoviv(); 
     } else { 
      throw error 
     } 
    } 

    method hash_subscript (idx) { 
     if (!content) { 
      content = new Hash(); 
     } 
     if (typeof content == Hash) { 
      if (exists content{idx}) return content{idx}; 
      return content{idx} = new autoviv(); 
     } else { 
      throw error 
     } 
    } 
    // overload all other access to return undefined, so that the value 
    // still looks empty for code like: 
    // 
    // var auto = new autoviv(); 
    // if (typeof auto[4] == autoviv) {should run} 
    // if (auto[4]) {should not run} 
} 
+3

이것은 자동 노출에 대한 좋은 설명이지만 실제 질문에는 대답하지 않습니다. – cjm

+1

@cjm => 다른 언어로 자동 가상화를 구현하기 위해 의사 코드로 업데이트되었습니다. getters 만, setter의 구현은 독자에게 달려 있습니다. –

+0

++, 내가 할 수만 있다면 +2, 그 예를 들면 'autovivification은 자동 진동이 없다면.' – Hugmeir

4

우리 구트 먼의 autovivification tutorial이 사용되었을 수 있습니다.

기본적으로 이전에 사용 된 손길이 닿지 않은 응집체 및 응집체 구성원은 처음 사용할 때 생기게됩니다.

예를 들어,이 작업을 수행 할 수 있습니다 그들은 역 참조하기 전에

#!/usr/bin/perl 

use strict; use warnings; 
use Data::Dumper; 

my @dummy; 

push @{ $dummy[0] }, split ' ', 'this that and the other'; 
push @{ $dummy[1] }, { qw(a b c d) }; 

print Dumper \@dummy; 

어느 $dummy[0]$dummy[1]이 존재한다. 만약 (는 안된다) strict을 포기하고자하는 경우

이제, 또한 할 수있는 같은 것들 : 그것은 중이므로 정의 변수 $x 배열 참조해진다

use Data::Dumper; 

@$x = qw(a b c d); 
print Dumper $x; 

을 역 참조. 미 설정 키에 []가 발생했을 때

+0

? 음 ... 뭐라구? 그게 무슨 뜻인지 확실하지 ... – Terrance

+1

"지금까지", 대략 – Hugmeir

+0

신경 쓰지 마라. 그 같은 실제 단어가 사용되었습니다 : 지금까지는이 시간까지 아무런 문제가 없었습니다 – Terrance

3

당신은, 말 만들기와 함께 반환 IDictionary<X,Y> (저장) 새로운 IDictionary<X,Y> (예를 들어, 반복적으로 동일한 유형) autovification 같은 동작을 구현할 수 있습니다. 이 접근법은 Ruby에서 대성공을 거두는 데 사용됩니다 (an example). 그러나 적어도 현존하는 대부분의 계약과 관련하여 리프 값을 깨끗하게 ""접근 할 수있는 방법이 없기 때문에 정적으로 유형이 지정된 언어에서는별로 유용하지 않습니다. 예 : IDictionary.

dynamic의 출현으로 C#에서는 위생적으로 할 수 있지만 가능하지는 않습니다.

+0

+1 Thx 시도입니다. 당신의 설명이 실제로 도움이되었습니다. – Terrance

1

어떻게 간단한 구현을 위해 이런 일에 대한 의 C#에서 사전의 동작과 같은 자동 vivification? 분명히 이것은 Perl이하는 일반적인 방식으로는 처리하지 않지만 같은 효과가 있다고 생각합니다.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

// The purpose of this class is to provide a dictionary with auto-vivification behaviour similar to Perl's 
// Using dict[index] will succeed regardless of whether index exists in the dictionary or not. 
// A default value can be set to be used as an initial value when the key doesn't exist in the dictionary 

namespace XMLTest 
{ 
    class AutoDictionary<TKey,TValue> : Dictionary<TKey,TValue> { 

     Object DefaultValue ; 

     public AutoDictionary(Object DefaultValue) { 
      this.DefaultValue = DefaultValue; 
     } 

     public AutoDictionary() { 
      this.DefaultValue = null; 
     } 

     public new TValue this[TKey index] { 
      get { 
       try { 
        return base[index]; 
       } 
       catch (KeyNotFoundException) { 
        base.Add(index, (TValue)DefaultValue); 
        return (TValue)DefaultValue ; 
       } 
      } 

      set { 
       try { 
        base[index] = value ; 
       } 
       catch (KeyNotFoundException) { 
        base.Add(index, value); 
       } 
      } 

     } 
    } 
} 
+0

당신의 솔직한 구현을 위해 고맙습니다. 존재하지 않으면 추가하십시오. – Terrance

0

상속 대신 확장 방법을 사용하는 것이 좋습니다.

class Tree 
{ 
    private IDictionary<string, object> dict = new Dictionary<string, object>(); 
    public dynamic this[string key] 
    { 
     get { return dict.ContainsKey(key) ? dict[key] : dict[key] = new Tree(); } 
     set { dict[key] = value; } 
    } 
} 

// Test: 
var t = new Tree(); 
t["first"]["second"]["third"] = "text"; 
Console.WriteLine(t["first"]["second"]["third"]); 

DynamicObject도 다른 구문을 구현하는 데 사용할 수 있습니다 인덱서 및 C# 4.0 역학을 사용

예컨대 :

namespace DictionaryEx 
{ 
    public static class Ex 
    { 
     public static TV Vivify<TK, TV>(this IDictionary<TK, TV> dict, TK key) 
     { 
      var value = default(TV); 
      if (dict.TryGetValue(key, out value)) 
      { 
       return value; 
      } 
      value = default(TV); 
      dict[key] = value; 
      return value; 
     } 

     public static TV Vivify<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue) 
     { 
      TV value; 
      if (dict.TryGetValue(key, out value)) 
      { 
       return value; 
      } 
      dict[key] = defaultValue; 
      return defaultValue; 
     } 

     public static TV Vivify<TK, TV>(this IDictionary<TK, TV> dict, TK key, Func<TV> valueFactory) 
     { 
      TV value; 
      if (dict.TryGetValue(key, out value)) 
      { 
       return value; 
      } 
      value = valueFactory(); 
      dict[key] = value; 
      return value; 
     } 
    } 
} 
0

, 완전히 떨어져

using System; 
using System.Collections.Generic; 
using System.Dynamic; 

class Tree : DynamicObject 
{ 
    private IDictionary<object, object> dict = new Dictionary<object, object>(); 

    // for t.first.second.third syntax 
    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     var key = binder.Name; 

     if (dict.ContainsKey(key)) 
      result = dict[key]; 
     else 
      dict[key] = result = new Tree(); 

     return true; 
    } 

    public override bool TrySetMember(SetMemberBinder binder, object value) 
    { 
     dict[binder.Name] = value; 
     return true; 
    } 

    // for t["first"]["second"]["third"] syntax 
    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) 
    { 
     var key = indexes[0]; 

     if (dict.ContainsKey(key)) 
      result = dict[key]; 
     else 
      dict[key] = result = new Tree(); 

     return true; 
    } 

    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) 
    { 
     dict[indexes[0]] = value; 
     return true; 
    } 
} 

// Test: 
dynamic t = new Tree(); 
t.first.second.third = "text"; 
Console.WriteLine(t.first.second.third); 

// or, 
dynamic t = new Tree(); 
t["first"]["second"]["third"] = "text"; 
Console.WriteLine(t["first"]["second"]["third"]);