简体   繁体   English

将用户输入的字符串转换为c#中的对象

[英]Convert user entered string into an object in c#

I have a battleship like terminal game, the user enters a coordinate like e2, and the program checks one of the instance variables of my object Box, it checks whether hasShip is true, if its true then it will make the coordinate e2 false, and give the output "Ship destroyed" 我有一个像终极游戏这样的战舰,用户输入了一个像e2这样的坐标,并且程序检查了我对象Box的实例变量之一,它检查hasShip是否为true,如果为true,那么它将使e2坐标为false,并且给输出“船毁坏”

The problem is that all my objects are called a1,a2,a3,a4,a5,b1,b2 and so on. 问题是我所有的对象都称为a1,a2,a3,a4,a5,b1,b2,依此类推。

I have created 25 instances of the Box class. 我已经创建了Box类的25个实例。 All names as such. 所有名称均如此。

Once the program gets input, either e4 ,e5 etc. I want to convert that string into an object. 一旦程序获得输入,要么e4,e5等。我想将该字符串转换为对象。

For example( I want to do something like this ) 例如(我想做这样的事情)

target = Console.ReadLine();
target.hasShip == true; 

I want to convert target into an object, then use target to use the methods of the Box class. 我想将target转换为对象,然后使用target使用Box类的方法。

Because the other approach requires me to make loads of if statements, which isn't clean code, doesn't look good, and is a waste if you ask me. 因为另一种方法要求我加载if语句的负载,这不是干净的代码,看起来也不好,如果您问我,这是浪费。

Thanks in advance, 提前致谢,


New Answer: use an Array 新答案:使用数组

I am slow. 我很慢 I did not pay attention that you are making a battleship-like game, and that we know that the "boxes" make a rectangle. 我没有注意到您正在制作类似战舰的游戏,而且我们知道“盒子”是矩形的。 We can store this efficiently in an array. 我们可以将其有效地存储在数组中。

Why I did not catch up to this fact earlier? 为什么我没有较早地了解这个事实? I guess I need to wake up properly. 我想我需要适当地醒来。

So, use an array: 因此,使用数组:

var board = new Box[5, 5];

Now, to populate it, we can do a double for loop: 现在,要填充它,我们可以执行double for循环:

for(var indexRow = 0; indexRow < 5; indexRow++)
{
    for(var indexCol = 0; indexCol < 5; indexCol++)
    {
        board[indexRow, indexCol] = new Box();
    }
}

Note : pay attention that the indexes go from 0 to 4. For a total of 5 values: {0, 1, 2, 3, 5}. 注意 :请注意索引从0到4。总共5个值:{0,1,2,3,5}。

And to query from it, we will need the indexes... 要从中查询,我们将需要索引...


Addendum on populating the array 填充数组的附录

In comments, OP has said that each Box has an id and the ship positions are picked at random. 在评论中,OP表示每个Box都有一个ID,并且随机选择了船只位置。

We can give the id in the loop: 我们可以在循环中给出id:

for(var indexRow = 0; indexRow < 5; indexRow++)
{
    for(var indexCol = 0; indexCol < 5; indexCol++)
    {
        var box = new Box();
        box.vhID = (((char)(((int)'a') + indexRow))).ToString() + ((char)(((int)'1') + indexCol)).ToString();
        board[indexRow, indexCol] = box;

    }
}

What I am doing here is constructing the id from the indexes. 我在这里所做的是从索引构造id。 Basically taking the value of 'a' and adding the indexRow will give us 'a' when indexRow is 0 , 'b' when it is 1 and so on. 基本上取'a'的值并加上indexRow将在indexRow0时给我们'a' ,在其为1时给我们'b' ,依此类推。 Similarly, we get the digit that represents the column. 同样,我们得到代表列的数字。

Note : We convert the char to int , do the addition, then convert back to char ... and then from char to string . 注意 :我们将char转换为int ,执行加法,然后转换回char ...,然后从charstring Once we have string, we can concatenate them. 一旦有了字符串,就可以将它们连接起来。

I do not think we need this id. 我认为我们不需要此ID。 But, hey, you can do it like this. 但是,嘿,您可以这样做。

OP also mentions that he will pick 4 ship positions at random. OP还提到他将随机选择4个船只位置。 Fair enough: 很公平:

var random = new Random();
for (var ships = 0; ships < 4; ships++)
{
    board[random.Next(0, 4), random.Next(0, 4)].hasShip = true;
}

Since the user inputs an string, I suggest to create a function to convert it to the index pair: 由于用户输入了字符串,因此建议创建一个函数以将其转换为索引对:

 var input = Console.ReadLine();
 if (TryGetCoordinates(input, out int irow, out int icol))
 {
     var target = board[irow, icol];
 }
 else
 {
     Console.WriteLine("The cell {0} does not exist.", input);
 }

 // ...

 bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
 {
     // ...
 }

Start by validating null : 首先验证null

 bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
 {
     indexRow = -1;
     indexCol = -1;
     if (cell == null)
     {
         return false;
     } 
     // ...
 }

Note : Feel free to use Trim , ToUpper or ToUpperInvariant . 注意 :可以随意使用TrimToUpperToUpperInvariant

We know that must be a letter followed by a digit, we can validate the length: 我们知道必须是字母后跟数字,我们可以验证长度:

 bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
 {
     indexRow = -1;
     indexCol = -1;
     if (cell == null)
     {
         return false;
     }
     if (cell.Length != 2)
     {
         return false;
     }
     // ...
 }

We extract the characters and from them the coordinates. 我们提取字符并从中提取坐标。 Noting that the first one is a letter, and the other a digit. 注意第一个是字母,另一个是数字。 We can also validate they are withing bounds. 我们还可以验证它们是否有界。

 bool TryGetCoordinates(string cell, out int indexRow, out int indexCol)
 {
     indexRow = -1;
     indexCol = -1;
     if (cell == null)
     {
         return false;
     }
     if (cell.Length != 2)
     {
         return false;
     }
     indexRow = (int)cell[0] - (int)'a';
     indexCol = (int)cell[1] - (int)'1';
     return indexRow < 5 && indexRow >= 0 && indexCol < 5 && indexCol >= 0;
 }

And of course, you can do a loop of the validation similar to what was explained in the old answer. 当然,您可以执行类似于旧答案中所述的验证循环。

Note : the issue with value types I describe in the old answer still applies with the array. 注意 :我在旧答案中描述的值类型问题仍然适用于数组。


Old Answer: Use a Dictionary 旧答案:使用字典

I believe you do not want to convert the string to an object (the string is an object by the way), you want to pick the Box object you previously created based on the string . 我相信您不想将string转换为对象(顺便说一句, string是一个对象),而是要选择先前基于string创建的Box对象。 And you want to do it without using if statements. 而且您想要不使用if语句就可以做到这一点。 What you need is a dictionary. 您需要一本字典。

So, you would have Dictionary<string, Box> meaning that it is a dictionary that you can query by string and stores Box . 因此,您将拥有Dictionary<string, Box> ,这意味着它是一个字典,您可以按字符串查询并存储Box

Addendums : 附录

  • In this case, string is the key type, by which we will access the dictionary. 在这种情况下,字符串是密钥类型,通过它我们可以访问字典。 When we add an object to the dictionary we identify it with a key, and when we retrieve it, we also use the key. 当我们在字典中添加一个对象时,我们用一个键来标识它,当我们检索它时,我们也使用键。 The key does not have to be string , you can choose a different type. 键不必是string ,您可以选择其他类型。 string is convenient in this case because it is what you get from Console.ReadLine() . 在这种情况下, string很方便,因为它是您从Console.ReadLine()
  • You can create the dictionary to store whatever type you need. 您可以创建字典来存储所需的任何类型。 If you do not need Box , you can create a dictionary that stores something else. 如果不需要Box ,则可以创建一个存储其他内容的字典。

Creating and populating the Dictionary 创建并填充字典

Then, you add to the Dictionary all your Box objects, like this: 然后,将所有Box对象添加到Dictionary中,如下所示:

var dict = new Dictionary<string, Box>();

// ...

dict.Add("a1", CreateBoxA1());

Where CreateBoxA1 represents whatever means you have to create the object. CreateBoxA1代表您必须创建对象的任何方式。 No, you do not need to create a method for each Box ... you can do it like this: 不,您不需要为每个Box创建一个方法...您可以这样操作:

dict.Add("a1", new Box());

Or whatever. 管他呢。 I do not know how you create them, so consider that a placeholder, ok? 我不知道您是如何创建它们的,所以考虑一个占位符,好吗? ok. 好。


Querying and retrieving values from the Dictionary 从字典中查询和检索值

Once you have all your Box instances in your dictionary, you can get the one you need using the string : 在字典中拥有所有Box实例后,就可以使用string获取所需的实例:

Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
var target = dict[name];

Addendum : The value you get from dict[name] is the value that you added to the dictionary with that key. 附录 :从dict[name]获得的值是使用该键添加到字典的值。 So, if the user typed "a1" it dict[name] will be the value that we added with "a1" ( dict.Add("a1", new Box()); ). 因此,如果用户键入"a1"dict[name]将是我们用"a1"添加的值( dict.Add("a1", new Box()); )。 Again, if what you need is not Box you can create a dictionary to store a different type. 同样,如果您不需要Box ,则可以创建字典来存储其他类型。


Input validation 输入验证

You can also use the Dictionary to validate if the string corresponds to a Box that exists, for example: 您还可以使用字典来验证string对应于存在的Box,例如:

Console.WriteLine("Enter the name of the Box:");
var name = Console.ReadLine();
if (dict.KeyExists(name))
{
    var target = dict[name];
    // ...
}
else
{
    Console.WriteLine("The Box {0} does not exist", name);
}

It goes without saying, but... you can make a loop based on that, for example: 不用说,但是...您可以基于此进行循环,例如:

Box target = null;
while(true)
{
    Console.WriteLine("Enter the name of the Box:");
    var name = Console.ReadLine();
    if (dict.KeyExists(name))
    {
        target = dict[name];
        break;
    }
    Console.WriteLine("The Box {0} does not exist", name);
}

Also, it goes without saying, but... you can add your own validations and sanitation steps. 另外,不用说,但是...您可以添加自己的验证和卫生步骤。 For example using ToUpper , ToUpperInvariant or Trim . 例如,使用ToUpperToUpperInvariantTrim And I would remind you that changing string s to lower or upper case is culture sensitive. 而且我想提醒您,将string s更改为小写或大写对文化敏感。

See also: Best Practices for Using Strings in .NET . 另请参见: 在.NET中使用字符串的最佳实践


Editing an removing objects from the dictionary 编辑字典中的删除对象

Once you have the object you retrieved from the Dictionary... 找到对象后,您便可以从“字典”中检索到该对象...

 var target = dict[name];

We can use it, and even modify it: 我们可以使用它,甚至可以对其进行修改:

 var target = dict[name];
 if (target.hasShip) // no need for "== true" if hasShip bool
 {
      target.hasShip = false;
      Console.WriteLine("Ship Destroyed");
 }

An special note must be done if Box is value type. 如果Box是值类型,则必须特别注意。 For a custom type that means that it is not a class but a struct . 对于自定义类型,这意味着它不是class而是struct The problem with value types is that they are copied on assignment, meaning that when you do var target = dict[name]; 值类型的问题在于它们是在赋值时复制的,这意味着在执行var target = dict[name]; with a value type, you get a copy. 使用值类型,您将获得一个副本。 You must then update the dictionary once you manipulated it: 然后,必须在操作字典后更新它:

 var target = dict[name];
 if (target.hasShip) // no need for "== true" if hasShip bool
 {
      target.hasShip = false;
      dict[name] = target;
      Console.WriteLine("Ship Destroyed");
 }

Note : As I said above, this is only needed for value types. 注意 :如上所述,这仅适用于值类型。


And you can even remove the Box from the dictionary if that is necesary: 如果需要,您甚至可以从字典中删除Box

dict.Remove(name); 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM