2012-04-27 130 views
3

在我們的應用程序中,我們有一些來自翻譯的字符串可以包含變量。例如在Can i have a {beverage}?{beverage}部分應該用變量替換。 我的當前實現通過使用所有變量的名稱和值的字典,並只替換正確的字符串。不過,我想通過引用來註冊變量,以便如果值被更改,結果字符串也會被更改。通常傳遞一個帶有ref關鍵字的參數可以做到這一點,但我不確定如何將這些參數存儲在字典中。參考字典值

TranslationParser:

static class TranslationParser 
{ 
    private const string regex = "{([a-z]+)}"; 
    private static Dictionary<string, object> variables = new Dictionary<string,object>(); 

    public static void RegisterVariable(string name, object value) 
    { 
     if (variables.ContainsKey(name)) 
      variables[name] = value; 
     else 
      variables.Add(name, value); 
    } 

    public static string ParseText(string text) 
    { 
     return Regex.Replace(text, regex, match => 
     { 
      string varName = match.Groups[1].Value; 

      if (variables.ContainsKey(varName)) 
       return variables[varName].ToString(); 
      else 
       return match.Value; 
     }); 
    } 
} 

main.cs

 string bev = "cola"; 
     TranslationParser.RegisterVariable("beverage", bev); 
     //Expected: "Can i have a cola?" 
     Console.WriteLine(TranslationParser.ParseText("Can i have a {beverage}?")); 
     bev = "fanta"; 
     //Expected: "Can i have a fanta?" 
     Console.WriteLine(TranslationParser.ParseText("Can i have a {beverage}?")); 

這是不可能的,還是我只是接近正確的問題?我擔心唯一的解決方案會涉及不安全的代碼(指針)。

因此,簡而言之,我想將一個變量存儲在字典中,更改原始變量並從字典中獲取已更改的值。就像你會用ref關鍵字一樣。

+0

http://en.wikipedia.org/wiki/Rope_(computer_science)可能會感興趣。 – 2012-04-27 11:51:06

+0

@DaveBish你是一個快速讀者!但那篇文章似乎是關於存儲,這不是一個問題。這些字符串來自xml文件,並且不包含在二進制文件中。 – TJHeuvel 2012-04-27 11:52:27

+0

和字符串操作似乎很好,我只是想基本上存儲在字典中的參考。 – TJHeuvel 2012-04-27 11:55:44

回答

1

使用包裝的另一種方式。每次註冊時都可以包裝變量。

class ObjectWrapper 
{ 
    private object _value; 

    public ObjectWrapper(object value) 
    { 
     _value = value; 
    } 

    public override string ToString() 
    { 
     return _value.ToString(); 
    } 
} 

static class TranslationParser 
{ 
    private const string regex = "{([a-z]+)}"; 
    private static Dictionary<string, ObjectWrapper> variables = new Dictionary<string, ObjectWrapper>(); 

    public static void RegisterVariable(string name, object value) 
    { 
     var wrapped = new ObjectWrapper(value); 
     if (variables.ContainsKey(name)) 
      variables[name] = wrapped; 
     else 
      variables.Add(name, wrapped); 
    } 

    public static string ParseText(string text) 
    { 
     return Regex.Replace(text, regex, match => 
     { 
      string varName = match.Groups[1].Value; 

      if (variables.ContainsKey(varName)) 
       return variables[varName].ToString(); 
      else 
       return match.Value; 
     }); 
    } 
} 

編輯:

但實際上,我認爲這是沒有不安全的代碼無法跟蹤你想要做的方式變量。值類型和對存儲在堆棧中的引用類型的引用,如果您只是替換引用,它不會影響堆中的實際對象(引用您存儲在字典中的對象)。所以你需要有引用(比如指針)來堆棧內存。

再次編輯:我錯了!

它可以跟蹤任何使用varaible表達式:

class Wrapper 
{ 
    private readonly Dictionary<string, MemberExpression> _registrations = 
     new Dictionary<string, MemberExpression>(); 

    public void Register<T>(string name, Expression<Func<T>> expr) 
    { 
     _registrations[name] = (MemberExpression)expr.Body; 
    } 

    public object GetValue(string name) 
    { 
     var expr = _registrations[name]; 
     var fieldInfo = (FieldInfo)expr.Member; 
     var obj = ((ConstantExpression)expr.Expression).Value; 
     return fieldInfo.GetValue(obj); 
    } 
} 
private static void Main(string[] args) 
{ 
    var wrapper = new Wrapper(); 
    int x = 0; 
    storage.Register("x",() => x); 
    Console.WriteLine(wrapper.GetValue("x")); //0 
    x = 1; 
    Console.WriteLine(wrapper.GetValue("x")); //1 
} 
+0

是的,就像rich.okelly也建議的那樣。測試和工作(upvoted以及;))。然而,它是一個相當嚴厲的,但如果它是唯一的方式。 – TJHeuvel 2012-04-27 12:20:41

+0

我想知道爲什麼有差異,是因爲自定義類是引用類型和System.String是一個值類型? – TJHeuvel 2012-04-27 12:21:09

+0

感謝您的明確答案:) – TJHeuvel 2012-04-27 13:49:45

0

在提供的代碼我看到

string bev = "cola"; 
TranslationParser.RegisterVariable("beverage", bev); 
//Expected: "Can i have a cola?" 
Console.WriteLine(TranslationParser.ParseText("Can i have a {beverage}?")); 
bev = "fanta"; 
//Expected: "Can i have a fanta?" 

第一你regitser的{飲料}的分別代替像"cola",但要在運行時改變它到另一個後:"fanta"。 Thie引導我思考:爲什麼不只是一個ParseText函數來接受一個可選參數,這將會對已保存的參數「獲勝」?

像這樣:

public static string ParseText(string text, string preferedValue=null) 
{ 
     return Regex.Replace(text, regex, match => 
     { 
      string varName = match.Groups[1].Value; 

      if (variables.ContainsKey(varName)) 
      { 
       if(!string.IsNullOrEmpty(preferedValue)) //IF THERE ISPREFERED VALUE               
         return preferedValue;    //RETURN THAT ONE 

       return variables[varName].ToString(); 
      } 
      else 
       return match.Value; 
     }); 
} 
+0

這將與普通的String.Format有所不同。事情是我不想知道一個地方的所有變量,應用程序的每個類都可以註冊新變量,而其他任何類都可以獲得翻譯。 – TJHeuvel 2012-04-27 12:05:56

+0

感謝您的建議,但:) – TJHeuvel 2012-04-27 12:07:28

+0

@TJHeuvel:好的,但看在帖子上,你看到你想有更多的靈活性,所以如果翻譯者的一個消費者的默認翻譯價值不好,它可以指定什麼對他更合適?這不正確嗎? – Tigran 2012-04-27 12:07:32