2017-05-06 454 views
1

[編輯:我加了很多細節,對這個問題,以使其更清晰,爲什麼我需要通過引用傳遞枚舉]通過引用的CreateInstance傳遞參數

我正在寫一些代碼,解析由命令和參數組成的列表。並非所有命令都具有相同數量的參數。例如,可以將清單 -

command1, 
100, 
command2, 
54, 
42, 
71, 
command3, 
10, 
31, 
command1, 
82, 
command3, 
102, 
87 

(請注意,某些命令可能有是非整數參數),我通過使用列表枚舉數據的列表迭代

。每個命令都有它自己的類,它能夠從列表中解析命令的參數(並執行一系列與此命令相關的其他活動,而這些活動並不需要用於此示例)。

我有一個命令連接到他們班一本字典 -

var map = new Dictionary<string, Type> 
{ 
    { "command1", typeof(Command1Class) }, 
    { "command2", typeof(Command2Class) }, 
    { "command3", typeof(Command3Class) }, 
}; 

所以我的基本的解析循環如下 -

var enumerator = data.GetEnumerator(); 
while (enumerator.MoveNext()) 
{ 
    var command = (string)enumerator.Current; 
    codeBlock.AddBlock((Block)Activator.CreateInstance(map[command], new object[] { enumerator })); 
} 

(所有命令類都從相同的基本類型派生的,塊)

因此,在每個命令類的構造函數中,它可以解析命令採用的參數的數量,並且在返回到主循環時,枚舉器將具有大量e通過這些參數繼續前進。

例如 -

class Command1Class : Block 
{ 
    string param; 

    public Command1Class(ref List<object>.Enumerator enumerator) 
    { 
     enumerator.MoveNext(); 
     param = (string)enumerator.Current; 
    } 
} 

但是我發現它枚舉器僅在構造函數中本地修改。因此,從構造函數返回時,枚舉器仍然指向命令,而不是繼續執行命令需要的參數。

如果我這樣做非動態使用下面的風格,它的工作原理與枚舉指向下一個命令時,它從構造函數返回預期 -

new SomeClass(ref enumerator) 

所以我不知道爲什麼我的代碼與CreateInstance不能按預期工作,我如何動態地做到這一點?

+0

你預期會發生什麼? – Evk

+0

「預期」是什麼? – Crowcoder

+0

你是對的。我已經添加了更多信息來說明這樣做的原因以及預期結果更加清晰 – Rok

回答

1

你的方法有很多問題,因爲Enumerator是struct(so,value type)。這意味着(除其他事項外),它被在許多情況下,如果你刪除ref關鍵字複製,例如:

public Command1Class(List<object>.Enumerator enumerator) 

然後通過你的枚舉 - 它會被複制和內部Command1Class構造枚舉是不一樣的實例作爲外部。你注意到了這一點,並通過引用在構造函數傳遞枚舉,但同樣的問題再次咬你,當你做到這一點:

(Block)Activator.CreateInstance(map[command], new object[] { enumerator }) 

您通過內部object[]陣列(如預期由CreateInstance)枚舉,而這又使得副本。是這樣的更加清晰:

var args = new object[] { enumerator }; 
Activator.CreateInstance(typeof(Command1Class), args); 

當您創建args陣列 - 它已經包含enumerator一個副本,而不是同一個實例。現在,這個副本是通過引用傳遞給你的構造,並確實先進,它可以驗證這樣的:

var args = new [] { enumerator }; 
Activator.CreateInstance(typeof(Command1Class), args); 
// assign copy back to original value 
enumerator = (List<object>.Enumerator) args[0]; 
// now enumerator is advanced as expected 

其實同樣會發生,如果enumerator是引用類型,因爲當你把它放在數組來傳遞參數到Activator.CreateInstance - 它不再是同一個變量(它指向內存中的同一個對象,但指針本身是不同的)。

所以你的方法是非常脆弱的,可能你應該重新設計它。如果你想堅持下來 - 不通過什麼構造,而是在Block類中創建方法:

public void Init(ref List<object>.Enumerator enumerator) 

然後調用它沒有反映。

+0

非常好的解釋 - 非常感謝。使用單獨的Init函數似乎是一個很好的解決方案,所以我會繼續。再次感謝 – Rok

0

不要使用引用你需要通過列表而不是引用枚舉器並在構造函數內調用getEnumerator。

class SomeClass 
{ 
    public SomeClass(List<object> list) 
    { 
     var enumerator = list.GetEnumerator(); 
     enumerator.MoveNext(); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var list = new List<object>(); 
     var someClass = Activator.CreateInstance(typeof(SomeClass), 
      new object[] { list = list }); 
    } 
} 
+0

感謝您的回覆。我爲原始問題添加了更多的細節,以便更清楚地說明爲什麼我需要通過引用以及我期待的結果來通過枚舉器 – Rok