【问题标题】:Creating dynamic variable names in C#在 C# 中创建动态变量名
【发布时间】:2012-08-09 20:23:40
【问题描述】:

我正在尝试用 C# 编写一个简单的角色扮演游戏以更加熟悉该语言。

我有一个从 CSV 文件加载数据、创建对象并将其放入字典的类。因为游戏的每个方面都有不同的数据(项目、演员、技能等),所以我将这些数据设置为一个类,但这需要我为每个数据重新实现一个 Load() 方法。在这样做了 5 或 6 次之后,我想知道是否有更好的方法来实现它。

基本上,我想要做的是解析包含标题的 CSV 的第一行,并将它们用作类变量名。目前,它们是作为字典关系实现的,所以我会使用 SomeClassInstance.dict["id"],理想情况下我会在其中键入 SomeClassInstance.id,它完全由文件的内容生成。

那是一回事吗?我该怎么做?

【问题讨论】:

  • 您可以使用反射来遍历类属性,测试属性名称是否与 CSV 列的名称匹配,然后设置值。也许 AutoMapper 可以提供帮助,但我不确定,您必须阅读一下有关它的信息
  • 不要为了简化持久性而在设计中搞砸!
  • @AndreCalil 这导致了一些非常丑陋的代码:pastebin.com/uK5E4XMS
  • @James (1) 丑陋的代码不一定是糟糕的代码。 (2) 无论如何,它都可以被重写为更漂亮。 (3) 当有人提出问题时,我不打算改变情景。如果 OP 使用 CSV 存储数据,那么请继续关注这个问题。我他问“有没有更好的持久性方法?”,事情会很不一样

标签: c# design-patterns dynamic csv


【解决方案1】:

如果您坚持当前的设计(CSV + 字典),您可以使用 ExpandoObject 类来获取您要查找的内容,创建一个简单的工厂类:

public static class ObjectFactory
{
    public static dynamic CreateInstance(Dictionary<string, string> objectFromFile)
    {
        dynamic instance = new ExpandoObject();

        var instanceDict = (IDictionary<string, object>)instance;

        foreach (var pair in objectFromFile)
        {
            instanceDict.Add(pair.Key, pair.Value);
        }

        return instance;
    }
}

这个工厂将创建一个你给它的任何字典的对象实例,即只有一种方法来创建你所有不同类型的对象。像这样使用它:

   // Simulating load of dictionary from file
   var actorFromFile = new Dictionary<string, string>();

   actorFromFile.Add("Id", "1");
   actorFromFile.Add("Age", "37");
   actorFromFile.Add("Name", "Angelina Jolie");

   // Instantiate dynamically
   dynamic actor = ObjectFactory.CreateInstance(actorFromFile);

   // Test using properties
   Console.WriteLine("Actor.Id = " + actor.Id + 
                     " Name = " + actor.Name + 
                     " Age = " + actor.Age);
   Console.ReadLine();

希望这会有所帮助。 (是的,她出生于 1975 年)

【讨论】:

  • 这很有趣。我喜欢这个主意,它似乎简化了一些事情。
【解决方案2】:

您需要阅读 serialization - 而不是将文件保存在 CSV 文件中,您可以将它们存储为序列化格式并将它们直接加载到所需的类型中。

您只需要几个方法来序列化和反序列化。

我建议阅读:

上面的链接指向不同的序列化程序(我当然遗漏了一些 - 任何知道的人,如果你知道有一个好的序列化程序,请添加) - 通读,查看他们的 API,使用它们和查看它们的磁盘格式并做出决定。

【讨论】:

    【解决方案3】:

    DynamicObject 派生并覆盖TryGetMember,以便它返回适当的字典条目。正是微软在 MVC 3 的 ViewBag 中所做的。 示例用法(如果您的派生类型被命名为CsvBag):

    dynamic bag = new CsvBag(csvFileStream);
    _monitor.Monster.LookUp(*bag.Id*).Attack(player); // whatever.. 
    

    【讨论】:

      【解决方案4】:

      为什么不创建一个负责读取数据并返回指定对象实例的管理器对象呢?比如:

      var actors = ActorsLoader.Load("actors.cvs");
      

      其中 ActorsLoader.Load 可以实现为:

      IEnumerable<Actor> Load( string fileName )
      {
          //1. reading each line (each line = new actor) & creating actor object
          //2. adding created actor object to a collection
          //3. returning back a collection
      }
      

      我假设每种类型的游戏内对象都存储在单独的文件中(因此您拥有:actors.csv、items.csv、skills.csv 等)

      【讨论】:

      • 实际上这正是我所拥有的(抱歉,如果我的 OP 帖子对此含糊不清)。它实际上是包含 的字典的 ActorData。但是,加载构造函数是不同的......我的不是 IEnumerable,而只是一个公共 void。
      • 抱歉误会。所以你真正想做的是完全摆脱序列化/反序列化代码?如果你想有一些自动反序列化机制,也许看看 ServiceStack 使用的 cvs de-serializer 会有帮助吗? servicestack.net/docs/text-serializers/json-csv-jsv-serializers
      • 我相信这可能是我想要的......我基本上想用文件中的数据动态创建一个类。就像,它的成员将完全从文件中确定。由于您的回答和其他一些人也提到了序列化,我想我应该进一步阅读。
      • 我不认为你可以序列化/反序列化动态对象,你必须创建常规的非动态类才能工作。
      猜你喜欢
      • 2021-10-26
      • 2011-10-27
      • 1970-01-01
      • 2021-12-31
      • 2014-09-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多