已回答 需要有关初始化对象中列表语法的帮助

邦德拉

知名会员
已加入
2020年10月24日
留言内容
74
编程经验
Beginner
这可能是一个明智的选择,但我只是无法解决这个问题。我创建了一个类和一个列表字段<T>.
但是停留在如何为特定列表键入正确的语法<T>创建对象时。

那么,在显示过载提示的屏幕快照中的逗号后面应该怎么办? :)

hlp.jpg
 
由主持人最后编辑:
Solution
至于这个问题,还有很多要解决的地方。首先,如果要使用自动属性,则无需定义自己的后备字段,因为自动属性会为您做到这一点。在过去,我们曾经不得不实现如下属性:
C#:
public class Player
{
    private string _name;
  
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value
        }
    }
}
如今,如果您在getter和setter中所做的只是获取并设置背景字段,则可以使用以下方法实现相同的结果:
C#:
public class Player
{
    public string Name { get; set; }
}
系统将实现getter,setter和...

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
首先,不要发布代码图片。它们很难在手机上阅读,如果要测试或显示修改后的版本,则无法复制和粘贴代码。我确实想向您展示代码的修改版本,但是现在我必须从头开始键入它,而不是复制您已有的内容并对其进行修改。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
至于这个问题,还有很多要解决的地方。首先,如果要使用自动属性,则无需定义自己的后备字段,因为自动属性会为您做到这一点。在过去,我们曾经不得不实现如下属性:
C#:
public class Player
{
    private string _name;
  
    public string Name
    {
        get
        {
            return _name;
        }
        set
        {
            _name = value
        }
    }
}
如今,如果您在getter和setter中所做的只是获取并设置背景字段,则可以使用以下方法实现相同的结果:
C#:
public class Player
{
    public string Name { get; set; }
}
The system will implement the getter, the setter and the backing field behind the scenes. If you look at the private members of the type, you'll find that you can actually access the implicitly declared field named _Name.

对于集合属性,您应该几乎总是将其声明为只读,然后在内部创建集合。这意味着调用代码可以获取现有集合,然后获取,设置,添加和删除项目,但是现有集合不能完全替换:
C#:
public class Player
{
    public string Name { get; set; }
    public List<int> Turns { get; } = new List<int>();
}
That's how it is throughout the .NET Framework already, with properties like Control.Controls, ComboBox.Items, DataTable.Rows, etc, etc.

在您的情况下,这意味着,如果您实际上不打算在集合中添加任何匝数,则无需关心构造函数中的该属性:
C#:
public class Player
{
    public string Name { get; set; }
    public bool PlayerIsComputer { get; set; }
    public int RoundsPlayed { get; set; }
    public List<int> Turns { get; } = new List<int>();

    public Player(string name, bool playerIsComputer, int roundsPlayed)
    {
        Name = name;
        PlayerIsComputer = playerIsComputer;
        RoundsPlayed = roundsPlayed;
    }
}
To be frank, I'm not sure why you would need the roundsPlayed parameter either. Won't that always be zero for a new Player? If so, there's no point using a parameter and you can just set the property explicitly to zero.

If there was a reason to pass in some existing values for Turns then you could do it like this:
C#:
public class Player
{
    public string Name { get; set; }
    public bool PlayerIsComputer { get; set; }
    public int RoundsPlayed { get; set; }
    public List<int> Turns { get; } = new List<int>();

    public Player(string name, bool playerIsComputer, int roundsPlayed)
    {
        Name = name;
        PlayerIsComputer = playerIsComputer;
        RoundsPlayed = roundsPlayed;
    }

    public Player(string name, bool playerIsComputer, int roundsPlayed, IEnumerable<int> turns)
        : this(name, playerIsComputer, roundsPlayed)
    {
        Turns.AddRange(turns);
    }
}
In that case, the second constructor invokes the first constructor to do the same thing with the first three parameters, then adds the turns values to the existing collection. You could then create a new Player like this:
C#:
players.Add(new Player(ShuffleName(), true, 0));
或像这样:
C#:
players.Add(new Player(ShuffleName(), true, 0, new [] {1, 2, 3}));
Because the turns parameter is type IEnumerable<int>, you can pass any type that implements that interface, which includes a 列表<int> or an int array or many other less common options.
 
Last edited:
解决方案

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
要回答所提出的问题,如果您要使用最初使用的代码(您绝对不应该使用),那么它将看起来像这样:
C#:
players.Add(new Player(SuffleName(), true, 0, new List<int>()));
 

邦德拉

知名会员
已加入
2020年10月24日
留言内容
74
编程经验
Beginner
非常感谢您抽出宝贵的时间!非常感激!

回合应该为每个回合存储玩家点数。所以是的,我想我可以摆脱roundsPlayed字段,并通过循环转弯列表来获得计数。
我目前正在相当基本的水平上研究C#,现在我们已经达到了OOP。从初学者的角度了解基础知识。您使用IEnumerable的解决方案是否是最好的基础知识? IEnumerables至少到目前为止还没有涉及到。

谢谢! :)
 
Last edited:

邦德拉

知名会员
已加入
2020年10月24日
留言内容
74
编程经验
Beginner
您会针对这种情况建议什么潜在的方式?
举例来说,对于一个玩家对象,我想跟踪每局打的局和局(其中1局= 3次掷飞镖的尝试)。就像是:
- 第1轮
- - 23
-- 14
-- 10
-第二轮
-- 10
-- 5
-- 1

最好的存储方式是什么?使用多个清单?一个拿着回合,另一个是"nested"在那个养育子女的名单上有分数吗?

这就是我最初制作类图的方式(希望可以将其作为图片):
捕获.png
 
Last edited:

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
回合应该为每个回合存储玩家点数。所以是的,我想我可以摆脱roundsPlayed字段,并通过循环转弯列表来获得计数。
I was just suggesting that there was no need for a parameter in the constructor, because that property would be initialised to zero every time. It's not such a bad idea to have a dedicated property for that but you should have a single source of truth. As it stands, it would be possible for the Turns collection to have a number of items that does not match the RoundsPlayed property. A better option would be to implement RoundsPlayed like this:
C#:
public int RoundsPlayed
{
    get
    {
        return Turns.Count;
    }
}
现在,您有了一个专用的属性,可以使调用代码清晰明了,但您知道它将始终与其他数据保持同步。
我目前正在相当基本的水平上研究C#,现在我们已经达到了OOP。从初学者的角度了解基础知识。您使用IEnumerable的解决方案是否是最好的基础知识? IEnumerables至少到目前为止还没有涉及到。
I guess it depends exactly what you consider to be the fundamentals. IEnumerable<T> is an interface and implementing interfaces is an important part of OOP, although probably a level or two up from basic. Essentially, any IEnumerable is a list that you can enumerate using a foreach loop and an IEnumerable<T> is a strongly-type version of that. In this case, the idea is that you can pass any enumerable list as an argument. You could declare that parameter as int[] or 列表<int> but then you are limited to passing in only one type of object when the actual functionality of the constructor doesn't require that type. If you want to stick with types that you've already covered though, by all means use one of those types.

话虽如此,这可能是有争议的,因为正如我所说,新球员一开始可能就没有回合,所以您永远不需要在这里传递任何东西。
 
Last edited:

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
您会针对这种情况建议什么潜在的方式?
举例来说,对于一个玩家对象,我想跟踪每局打的局和局(其中1局= 3次掷飞镖的尝试)。就像是:
- 第1轮
- - 23
-- 14
-- 10
-第二轮
-- 10
-- 5
-- 1

最好的存储方式是什么?使用多个清单?一个拿着回合,另一个是"nested"在那个养育子女的名单上有分数吗?

这就是我最初制作类图的方式(希望可以将其作为图片):
查看附件1152
You might define a Round class that had a property each for the three attempts and then a property for the sum of those scores. Your Player class could then have a Rounds property that was a 列表<Round>. You might even have a TotalScore property that was implemented as a sum of the scores for all rounds.
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
You might define a Round class that had a property each for the three attempts and then a property for the sum of those scores. Your Player class could then have a Rounds property that was a 列表<Round>. You might even have a TotalScore property that was implemented as a sum of the scores for all rounds.
我同意拥有一个带有三个属性的回合类来保存每个回合的值。 @jmcilhinney 在读我的思想,但在思考方面比我领先...这很接近 @jmcilhinney 毕竟是在建议,希望它没问题。您可以在早上04:30向男人期望什么类型的伪代码 :) :
C#:
        public class Game
        {
            public Player AddPlayer(Player player)
            {
                return player;
            }
            public Player RemovePlayer(Player player)
            {
                return player;
            }
            public Player CreateAIPlayer(Player player)
            {
                return player;
            }
            public void BeginGame()
            {

            }
        }
        public class Player
        {
            public Player(int roundsPlayed, string playerName, double playerScore, RoundScores roundScores, bool playerIsAI)
            {
                RoundsPlayed = roundsPlayed;
                PlayerName = playerName;
                PlayerScore = playerScore;
                RoundScores = roundScores;
                PlayerIsAI = playerIsAI;
            }
            public int RoundsPlayed { get; set; }
            public string PlayerName { get; set; }
            public double PlayerScore { get; set; }
            public RoundScores RoundScores { get; set; }
            public bool PlayerIsAI { get; set; }
        }
        public class Score
        {
            public Score(double totalScore)
            {
                TotalScore = totalScore;
            }
            public double GetTotalScore(RoundScores roundScores)
            {
                TotalScore = roundScores.Round1Score + roundScores.Round2Score + roundScores.Round3Score;
                return TotalScore;
            }
            public List<Score> ScoresList = new List<Score>();
            public double TotalScore { get; set; }
        }
        public class RoundScores
        {
            public double Round1Score { get; set; }
            public double Round2Score { get; set; }
            public double Round3Score { get; set; }
        }
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,926
地点
英国
编程经验
10+
询问任何问题,如果您不了解某些内容。我们毕竟是在这里尽力帮助和指导您。但是,自从我今天早上04:30写下这句话以来,有一件事:
C#:
public class Score { public Score(double totalScore) { TotalScore = totalScore; }
public double GetTotalScore(RoundScores roundScores)
{
TotalScore = roundScores.Round1Score + roundScores.Round2Score + roundScores.Round3Score; return TotalScore;
}
public List<Score> ScoresList = new List<Score>();
public double TotalScore { get; set; } }
该GetTotalScore并不真正属于那里。每当使用用于存储数据的类时,最好仅出于该目的使用该类。相反,请将您拥有的所有方法转储到另一个单独的类中,甚至转储到某种类型的静态助手中以保存您的方法。它不仅使代码更整洁;因为它也有助于保持班级结构的单一责任规则。因此,我在其中鞭打错误。
 

邦德拉

知名会员
已加入
2020年10月24日
留言内容
74
编程经验
Beginner
我玩耍并取得了一些小进展。
我不知道,如何才能实现下面圆圈中的结构?至少对我来说,它看起来更有条理。不了解以这种方式收集它的最佳实践。看起来像某种嵌套列表?您对此有何看法?

编辑:计数= 41是错误的。但是你了解结构 :)

无标题-2.jpg
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,524
地点
悉尼,澳大利亚
编程经验
10+
一切都已经涵盖了。
C#:
using System.Collections.Generic;

namespace ConsoleApp1
{
    public class Program
    {
        public static void Main()
        {
            var p = new Player();
            var r = new Round();

            r.FirstAttempt = 16;
            r.SecondAttempt = 5;
            r.ThirdAttempt = 20;

            p.RoundsPlayed.Add(r);
        }
    }

    public class Player
    {
        public List<Round> RoundsPlayed { get; } = new List<Round>();
    }

    public class Round
    {
        public int FirstAttempt { get; set; }
        public int SecondAttempt { get; set; }
        public int ThirdAttempt { get; set; }
    }
}
 

邦德拉

知名会员
已加入
2020年10月24日
留言内容
74
编程经验
Beginner
非常感谢!如此简单干净!
预先尝试使用自己的解决方案,确实可以帮助我更好地了解我要实现的目标。这也使得最终掌握您的建议更加容易 :)
 
最佳 底部