【问题标题】:How to get the specified value from a List<T> and T is a generic class?如何从 List<T> 中获取指定值并且 T 是泛型类?
【发布时间】:2021-05-26 20:17:06
【问题描述】:

假设我们有一个带有泛型数组的 Container 类

public class Container<T>
{
    public T[] ObjectArray = new T[];
}

public class PlayerInfo
{
    public int level;
    public string playerName;
    public string description
}

public class EnemyInfo
{
    public string enemyName;
}

现在我的应用中有Container&lt;PlayerInfo&gt;Container&lt;EnemyInfo&gt;,它们有很多玩家/敌人数据。

我想创建一个List来处理我的应用程序中的所有Container,并打印出所有string类型的字段,我该如何实现呢?

以上面的例子我要打印出playerNamedescriptionenemyName

我试过是这样的。

//let container inherit from a class
public class Container<T> : BaseClass
{
    public T[] ObjectArray = new T[];
}

//so that I could add them to a single list.
var list = new List<BaseClass>();
list.Add(playerContainerInstance);
list.Add(enemyContainerInstance);

foreach(var element in list)
{
    //and what should I do now to get string field from it?
}

现在我可以弄清楚是用反射做一些事情,但也许还有另一种方法可以做到这一点?

【问题讨论】:

  • 我认为更好的方法是不要使用无意义的超泛型容器类。如果你需要一个收藏来持有PlayerInfos,声明一个;如果出于某种原因必须将多个不同类型的容器存储在一个地方,则可以有一个类来保存多个类型化的属性(每个属性本身都可以是容器、字典或诸如此类的东西)。我很难想出在哪些实际场景中存储多个容器是有意义的,每个容器都有不同的、不兼容的类型,并且仍然有意义地处理它们。
  • 至于打印字符串的一般机制:您可以强制执行类应该覆盖.ToString() 以提供有意义的表示的约定,然后调用它;这有利于为任何object 工作。编写一个通用的.ToString() 使用反射来输出所有属性值也不是太难,所以如果你不想的话,你不必为每个类都重做。

标签: c# generics reflection


【解决方案1】:

好吧,如果你想从特定类型中获取特定属性,例如 enemyName 来自 EnemyInfo 和玩家相同(所以他们不共享基类中的那些),我想你需要强制转换它们/ 检查类型,然后采取相应措施。

应该这样做:

foreach(var element in list)
{
   if(element is EnemyInfo enemy)
   {
     // print out 
     enemy.enemyName
   }
   else if(element is PlayerInfo player)
   {
     // print out
     player.playerName;
     player.description;
   }
}

作为一般建议,由于敌人和玩家都有名字,所以有一个基类 f.e. BaseInfo,它有一个proptery name,玩家和敌人可以继承,所以你不需要转换,如果你只是想得到名字:

public class BaseInfo
{
    public string EntityName;
}

public class PlayerInfo : BaseInfo
{
    public int level;
    public string description
}

public class EnemyInfo : BaseInfo
{
  // Have more specific enemy stuff here....
}

然后,您可以: 应该这样做:

foreach(var element in list)
{
  print element.EntityName;

  // Then cast if necessary for more specific types.


   if(element is EnemyInfo enemy)
   {
    /// ...
   }
   else if(element is PlayerInfo player)
   {
    /// ...
    player.description;
   }
}

【讨论】:

  • 理想情况下这样做更有意义,但实际上我得到了数百个类似于PlayerInfo的类,不可能一个一个处理。所以我仍然需要一种更通用的方法来做到这一点:(。
【解决方案2】:

如果您想要对象的字符串表示,一个简单且易于理解的解决方案是将其转换为 JSON 字符串:

foreach (var item in container.ObjectArray)
{
    Console.WriteLine(JsonConvert.SerializeObject(item));
}

这将为每个项目输出一个字符串,每个字符串包含每个项目的所有属性,无论类型如何。

如果您不喜欢 JSON 格式,则必须决定自己的自定义格式,并编写自己的序列化程序(最终可能不得不使用反射)。但是原理还是一样的。

【讨论】:

  • 我的对象的字符串表示不是我需要的。我需要对象中“字符串”类型的字段(例如 playerName,但不是级别)。
猜你喜欢
  • 1970-01-01
  • 2016-08-24
  • 2022-12-17
  • 2012-11-28
  • 1970-01-01
  • 1970-01-01
  • 2021-09-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多