2010-12-21 20 views
0

perlのAutovivificationの周りを頭で囲み、それがどういうふうに聞こえるかに基づいて、動的オブジェクトは実行時まで型に割り当てられていないので、C#の動力学と似ているようです。もしそうなら、には、私がCで橋渡しすることができるという匹敵する考えがあります。それは意味がありますか?


私は明らかに道のりです。だから、2つの部分の質問の第2部分として、概念的にはC#で比較できるものはありますか?明確にするために、私はC#のコンセプトを探しています。これはAutovivificationに匹敵します。まったく同じである必要はありませんが、理にかなって概念的には十分に近いです。そして、私はイーライラを述べたので、私は決して想像力の広がりによって決してパールハッカーまたはパイソンハッカーではないが、私はC言語、C++、C#、java、javascriptに慣れている。私はC#の動力学を考えていましたが、今のところ、ここで情報に基づいて怠惰なローディングを考えています。Cでの自動化#

+3

。 http://en.wikipedia.org/wiki/Autovivificationを参照してください – mob

+0

ええ、そこにいたが、私は非常にPerlの難解な部分のいくつかにはあまり流暢ではないので、Pythonので – Terrance

+0

+1私は完全にオフです笑。どこかで始まらなければならない... – Terrance

答えて

9

私はC#と話すことはできませんが、一般人の言葉で言えば、Perlの自動化は、必要に応じてすぐに未定義の値からコンテナオブジェクトを作成するプロセスです。

ほとんどのPerlは非常に動的ですが、Perlの参照外構文では、コンパイル時に参照の種類が明白に指定されています。これにより、インタプリタは、変数が定義される前に変数から必要なものを知ることができます。

このリストはもっと長くなるかもしれませんが、あなたには分かります。そこで、基本的

、次のような行を持っている場合:

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

Perlは->の右側に見て、角括弧を見ています。つまり、呼び出し元$varは配列参照でなければなりません。 invocantが定義されていないので、Perlは新しい配列を作成し、その参照を$varにインストールします。この同じプロセスは、その後の逆参照のたびに繰り返されます。

したがって、上記の行は、本当に意味:

ので、autovivificationかなり恐ろしいです、と
 
    (((($var //= [])->[1] //= {})->{x} //= [])->[3] //= {})->{asdf}; 

を。あなたが必要とする、別の言語でautovivificationを達成するために、一般的な非perlの条項にこれを入れて、CJMのコメントを1として

:更新

//=は5.10+ Perlで定義された、または代入演算子です) [...]{...}によってインデックスをサポートする遅延オブジェクトです。これらの索引付け操作のいずれかが実行されると、オブジェクトは配列またはハッシュのいずれかに置き換えられます。オブジェクトがアクセスされるたびに、セルが空の場合は、別の遅延オブジェクトを返す必要があります。

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 =>別の言語の自動ウイルス対策を実装するために疑似コードで更新されました。 getterのみ、setterの実装は読者に委ねられます。 –

+0

++、もし私ができるなら、私は+2にすることができます。 – 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を見合わせることを喜んでいる場合、あなたはまた、のようなものを行うことができます:それはされているため

use Data::Dumper; 

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

を未定義の変数$xは、配列の参照となりますそのように逆参照される。

+0

?ええと...何?それが何を意味するかわからない... – Terrance

+1

「今まで」、おおよそ – Hugmeir

+0

心配しないでください。実際にこの言葉として使用されていたその言葉:今までこれまでに問題はなかった – Terrance

3

解除キーへ[]が発生したときにあなたは返し(格納)IDictionary<X,Y>、新しいIDictionary<X,Y>(例えば再帰的に同じタイプを)言うの作成とautovificationのような振る舞いを実装することができます。このアプローチは、大成功(an example)にRubyで使用されている - 少なくとも、ほとんどの既存の契約のコンテキストで - きれいリーフ値「を取得」する方法がないためしかし、それは静的型付け言語で本当に便利ではありません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"]);