2012-04-27 100 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