如何构造一个对象来表示主题列表?
How to struct an object to represent a list of topics?
我正在使用 C# 进行编码,我正在尝试制作主题列表的 OOP 表示。我尝试了无数方法,但仍然无法达到预期的结果。
我想稍后制作一个输出如下的方法:
1) Text
1.1) Text
2) Text
2.1) Text
2.2) Text
2.2.1) Text
2.2.2) Text
2.3) Text
3) Text
3.1) Text
当需要获取单个主题时,我想创建一个调用我的对象的方法,例如:
private string GetSingleTopic()
{
return $"{Topic.Numerator}) {Topic.Text}"
}
例子
示例 1
我将能够实例化对象,例如:
var variable = new TopicObject
{
"TitleA",
"TitleB",
"TitleC"
}
/* --- OUTPUT ---
1) TitleA
2) TitleB
3) TitleC
--- OUTPUT --- */
示例 2
能够实例化对象如:
var variable = new TopicObject
{
"TitleA",
"TitleB",
"TitleC":
{
"TitleD":
{
"TitleE"
},
"TitleF":
{
"TitleG",
"TitleH"
}
}
}
/* --- OUTPUT ---
1) TitleA
2) TitleB
3) TitleC
3.1) TitleD
3.1.2) TitleE
3.2) TitleF
3.2.1) TitleG
3.2.2) TitleH
--- OUTPUT --- */
我的方法
这是我的众多方法之一。我无法使用它,因为我无法按照我提到的方式初始化内部主题列表,例如层次结构。
但结构与我想要实现的非常相似,所以我决定放在这里作为示例。
public abstract class TopicBase
{
public List<Topic> Topics { get; set; } // optional
protected TopicBase() { Topics = new List<Topic>(); }
protected TopicBase(List<Topic> topics) { Topics = topics; }
public TopicBase AddTopic(string topicText)
{
var test = new Topic(topicText);
Topics.Add(test);
return this;
}
}
public class Topic
{
public Topic(string text)
{
Numerator++;
Text = text;
}
public int Numerator { get; }
public string Text { get; }
}
public class TopicLevel1 : TopicBase { }
public class TopicLevel2 : TopicBase { }
public class TopicLevel3 : TopicBase { }
如果目标是一些 有助于输出主题层次结构的结构,您已经拥有它(甚至可以进一步简化它)。
例如,这里有一个几乎-最小Topic
来得到你想要的:
public class Topic
{
public string Title { get; set; }
public List<Topic> SubTopics { get; private set; } = new();
public Topic() : this("DocRoot") { }
public Topic(string title) => Title = title;
public void AddTopics(List<Topic> subTopics) => SubTopics.AddRange(subTopics);
public void AddTopics(params Topic[] subTopics) => SubTopics.AddRange(subTopics);
public override string ToString() => Title;
}
也就是说,您有一个 Topic
可以有 SubTopics
(又名 children),这就是您 所需要的。
这样,我们就可以构建您的第二个示例:
var firstLevelTopics = new List<Topic>();
for (var c = 'A'; c < 'D'; ++c)
{
firstLevelTopics.Add(new Topic(c.ToString()));
}
var cTopic = firstLevelTopics.Last();
cTopic.AddTopics(
new Topic
{
Title = "D",
SubTopics = { new Topic("E") }
},
new Topic
{
Title = "F",
SubTopics = { new Topic("G"), new Topic("H") }
});
现在,想象一下,如果我们有一个函数来打印 top-level 主题列表中的层次结构。我将把最后的细节留给你自己,以防这是作业。
PrintTopics(firstLevelTopics);
static void PrintTopics(List<Topic> topics, string prefix = "")
{
// For the simple case, we can just loop and print...
for (var i = 0; i < topics.Count; ++i)
{
var topic = topics[i];
var level = i + 1;
Console.WriteLine($"{prefix}{level}) {topic}");
// ...but, if we want to print the children, we need more.
// Make a recursive call to print the SubTopics
// PrintTopics(<What goes here?>);
}
}
让我们从定义一个可以容纳主题的数据结构开始:
public class Topics<T> : List<Topic<T>> { }
public class Topic<T> : List<Topic<T>>
{
public T Value { get; private set; }
public Topic(T value, params Topic<T>[] children)
{
this.Value = value;
if (children != null)
this.AddRange(children);
}
}
这让我们可以编写这段代码:
var topics = new Topics<string>()
{
new Topic<string>("TitleA"),
new Topic<string>("TitleB"),
new Topic<string>("TitleC",
new Topic<string>("TitleD",
new Topic<string>("TitleE")),
new Topic<string>("TitleF",
new Topic<string>("TitleF"),
new Topic<string>("TitleH")))
};
与您的“示例 2”数据匹配。
为了输出结果,我们添加了两个 ToOutput
方法。
至Topics<T>
:
public IEnumerable<string> ToOutput(Func<T, string> format)
=> this.SelectMany((t, n) => t.ToOutput(0, $"{n + 1}", format));
至Topic<T>
:
public IEnumerable<string> ToOutput(int depth, string prefix, Func<T, string> format)
{
yield return $"{new string(' ', depth)}{prefix}) {format(this.Value)}";
foreach (var child in this.SelectMany((t, n) => t.ToOutput(depth + 1, $"{prefix}.{n + 1}", format)))
{
yield return child;
}
}
现在我可以运行这个代码:
foreach (var line in topics.ToOutput(x => x))
{
Console.WriteLine(line);
}
这给了我:
1) TitleA
2) TitleB
3) TitleC
3.1) TitleD
3.1.1) TitleE
3.2) TitleF
3.2.1) TitleF
3.2.2) TitleH
我正在使用 C# 进行编码,我正在尝试制作主题列表的 OOP 表示。我尝试了无数方法,但仍然无法达到预期的结果。
我想稍后制作一个输出如下的方法:
1) Text
1.1) Text
2) Text
2.1) Text
2.2) Text
2.2.1) Text
2.2.2) Text
2.3) Text
3) Text
3.1) Text
当需要获取单个主题时,我想创建一个调用我的对象的方法,例如:
private string GetSingleTopic()
{
return $"{Topic.Numerator}) {Topic.Text}"
}
例子
示例 1
我将能够实例化对象,例如:
var variable = new TopicObject
{
"TitleA",
"TitleB",
"TitleC"
}
/* --- OUTPUT ---
1) TitleA
2) TitleB
3) TitleC
--- OUTPUT --- */
示例 2
能够实例化对象如:
var variable = new TopicObject
{
"TitleA",
"TitleB",
"TitleC":
{
"TitleD":
{
"TitleE"
},
"TitleF":
{
"TitleG",
"TitleH"
}
}
}
/* --- OUTPUT ---
1) TitleA
2) TitleB
3) TitleC
3.1) TitleD
3.1.2) TitleE
3.2) TitleF
3.2.1) TitleG
3.2.2) TitleH
--- OUTPUT --- */
我的方法
这是我的众多方法之一。我无法使用它,因为我无法按照我提到的方式初始化内部主题列表,例如层次结构。 但结构与我想要实现的非常相似,所以我决定放在这里作为示例。
public abstract class TopicBase
{
public List<Topic> Topics { get; set; } // optional
protected TopicBase() { Topics = new List<Topic>(); }
protected TopicBase(List<Topic> topics) { Topics = topics; }
public TopicBase AddTopic(string topicText)
{
var test = new Topic(topicText);
Topics.Add(test);
return this;
}
}
public class Topic
{
public Topic(string text)
{
Numerator++;
Text = text;
}
public int Numerator { get; }
public string Text { get; }
}
public class TopicLevel1 : TopicBase { }
public class TopicLevel2 : TopicBase { }
public class TopicLevel3 : TopicBase { }
如果目标是一些 有助于输出主题层次结构的结构,您已经拥有它(甚至可以进一步简化它)。
例如,这里有一个几乎-最小Topic
来得到你想要的:
public class Topic
{
public string Title { get; set; }
public List<Topic> SubTopics { get; private set; } = new();
public Topic() : this("DocRoot") { }
public Topic(string title) => Title = title;
public void AddTopics(List<Topic> subTopics) => SubTopics.AddRange(subTopics);
public void AddTopics(params Topic[] subTopics) => SubTopics.AddRange(subTopics);
public override string ToString() => Title;
}
也就是说,您有一个 Topic
可以有 SubTopics
(又名 children),这就是您 所需要的。
这样,我们就可以构建您的第二个示例:
var firstLevelTopics = new List<Topic>();
for (var c = 'A'; c < 'D'; ++c)
{
firstLevelTopics.Add(new Topic(c.ToString()));
}
var cTopic = firstLevelTopics.Last();
cTopic.AddTopics(
new Topic
{
Title = "D",
SubTopics = { new Topic("E") }
},
new Topic
{
Title = "F",
SubTopics = { new Topic("G"), new Topic("H") }
});
现在,想象一下,如果我们有一个函数来打印 top-level 主题列表中的层次结构。我将把最后的细节留给你自己,以防这是作业。
PrintTopics(firstLevelTopics);
static void PrintTopics(List<Topic> topics, string prefix = "")
{
// For the simple case, we can just loop and print...
for (var i = 0; i < topics.Count; ++i)
{
var topic = topics[i];
var level = i + 1;
Console.WriteLine($"{prefix}{level}) {topic}");
// ...but, if we want to print the children, we need more.
// Make a recursive call to print the SubTopics
// PrintTopics(<What goes here?>);
}
}
让我们从定义一个可以容纳主题的数据结构开始:
public class Topics<T> : List<Topic<T>> { }
public class Topic<T> : List<Topic<T>>
{
public T Value { get; private set; }
public Topic(T value, params Topic<T>[] children)
{
this.Value = value;
if (children != null)
this.AddRange(children);
}
}
这让我们可以编写这段代码:
var topics = new Topics<string>()
{
new Topic<string>("TitleA"),
new Topic<string>("TitleB"),
new Topic<string>("TitleC",
new Topic<string>("TitleD",
new Topic<string>("TitleE")),
new Topic<string>("TitleF",
new Topic<string>("TitleF"),
new Topic<string>("TitleH")))
};
与您的“示例 2”数据匹配。
为了输出结果,我们添加了两个 ToOutput
方法。
至Topics<T>
:
public IEnumerable<string> ToOutput(Func<T, string> format)
=> this.SelectMany((t, n) => t.ToOutput(0, $"{n + 1}", format));
至Topic<T>
:
public IEnumerable<string> ToOutput(int depth, string prefix, Func<T, string> format)
{
yield return $"{new string(' ', depth)}{prefix}) {format(this.Value)}";
foreach (var child in this.SelectMany((t, n) => t.ToOutput(depth + 1, $"{prefix}.{n + 1}", format)))
{
yield return child;
}
}
现在我可以运行这个代码:
foreach (var line in topics.ToOutput(x => x))
{
Console.WriteLine(line);
}
这给了我:
1) TitleA
2) TitleB
3) TitleC
3.1) TitleD
3.1.1) TitleE
3.2) TitleF
3.2.1) TitleF
3.2.2) TitleH