-1

Let's say if we have a Container class with generic array

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;
}

Now I have Container<PlayerInfo> and Container<EnemyInfo> in my app, which have lots of player/enemy data.

I want to create a List to handle all Container in my app, and print out all fields which are string type, how could I achieve it?

Take the above example I want to print out playerName description enemyName.

What I've tried is like this.

//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?
}

For now I can figure out is do something with reflection, but maybe there is another way to do this?

CloudL
  • 201
  • 1
  • 5
  • 16
  • 1
    Does this answer your question? [How to create List of open generic type of class?](https://stackoverflow.com/questions/58570948/how-to-create-list-of-open-generic-type-of-classt) and [How to do generic polymorphism on open types in C#?](https://stackoverflow.com/questions/58247604/how-to-do-generic-polymorphism-on-open-types-in-c/58247676) –  May 26 '21 at 20:22
  • 2
    I'd argue the better way is to not have meaningless, super-generic container classes. If you need a collection to hold `PlayerInfo`s, declare one; if you must store multiple containers of different types in one place for some reason, you could have a class to hold multiple typed properties (and each of those could themselves be containers, dictionaries or whatnot). I have a hard time thinking up actual scenarios where it makes sense to store multiple containers, each with different, incompatible types in one place and still meaningfully process them. – Jeroen Mostert May 26 '21 at 20:22
  • 2
    As for a general mechanism to print out strings: you could just enforce the convention that classes should override `.ToString()` to give meaningful representations, and call that; that has the benefit of working for any `object`. Writing a generic `.ToString()` that coughs up all property values using reflection isn't too hard either, so you don't have to redo that for every class if you don't want to. – Jeroen Mostert May 26 '21 at 20:26

2 Answers2

0

Well, if you are looking to get specific properties from specific types, for example enemyName from EnemyInfo and the same for player (so they dont share those from a base class), I guess you need to cast them / check for type and then act accordingly.

Something like this should do:

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;
   }
}

As a general advice, since enemy and player have a name, have a base Class f.e. BaseInfo, which has a proptery name, where player and enemy can inherit from, so you dont need to cast, if you just wanna get the 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....
}

Then, you can do: Something like this should do:

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;
   }
}
Zokka
  • 147
  • 6
  • Ideally this does makes more sense, but in fact I got hundreds of class similar to PlayerInfo, and it's impossible to handle it one by one. So I still need a more generic way to do this :(. – CloudL May 26 '21 at 20:41
0

If you want a string representation of your objects, a simple and well-understood solution would be to convert it to a JSON string:

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

This will output one string per item, with each string containing all of the properties of each item, regardless of the type.

If you don't like the JSON format, you will have to decide on a custom format of your own, and write your own serializer (which would probably end up having to use reflection). But the principle would remain the same.

John Wu
  • 50,556
  • 8
  • 44
  • 80
  • string representation of my objects are not what I need. I need the field which is in the type of "string" in object (e.g. playerName, but not level). – CloudL May 27 '21 at 02:21