Просто потому, что я думаю, что другие ответы в значительной степени касаются касательной того, является ли футбольная команда «is-a» List<FootballPlayer>
или «has-a» List<FootballPlayer>
, которая на самом деле не отвечает на этот вопрос, как написано .
ОП в основном просит уточнить принципы наследования с List<T>
:
. В руководстве говорится, что вы не должны наследовать
blockquote>List<T>
. Почему нет?Поскольку
List<T>
не имеет виртуальных методов. Это меньше проблем в вашем собственном коде, поскольку вы обычно можете отключить реализацию с относительно небольшой болью, но может быть гораздо более крупной сделкой в публичном API.Что такое публикация API и почему мне это нужно?
blockquote>Открытый API - это интерфейс, который вы предоставляете сторонним программистам. Подумайте о каркасе. И помните, что ссылки, на которые ссылаются, - это «Рекомендации по дизайну .NET Framework », а не «Рекомендации по дизайну .NET ». Существует разница, и, вообще говоря, публичный дизайн API гораздо более строгий.
Если мой текущий проект не имеет и вряд ли когда-либо будет иметь этот открытый API, могу ли я безопасно игнорировать это руководство? Если я наследую List, и мне кажется, что мне нужен публичный API, какие трудности у меня есть?
blockquote>В значительной степени, да. Возможно, вам стоит подумать об обоснованности этого вопроса, чтобы убедиться, что оно применимо к вашей ситуации в любом случае, но если вы не создаете публичный API, вам не нужно беспокоиться об особенностях API, таких как управление версиями (из которых это подмножество).
Если вы добавите публичный API в будущем, вам нужно будет либо абстрагировать свой API от вашей реализации (не подвергая непосредственно ваше
List<T>
), либо нарушать рекомендации с возможным будущим боль, которая влечет за собой.Почему это даже имеет значение? Список - это список. Что может измениться? Что я могу изменить?
blockquote>Зависит от контекста, но поскольку мы используем
FootballTeam
в качестве примера - представьте, что вы не можете добавитьFootballPlayer
, если он приведет к тому, что команда перейдет на зарплату. Возможный способ добавить это будет следующим:class FootballTeam : List<FootballPlayer> { override void Add(FootballPlayer player) { if (this.Sum(p => p.Salary) + player.Salary > SALARY_CAP)) { throw new InvalidOperationException("Would exceed salary cap!"); } } }
А ... но вы не можете
override Add
, потому что это неvirtual
(по соображениям производительности).Если вы находитесь в приложении (которое в основном означает, что вы и все ваши собеседники скомпилированы вместе), вы можете теперь изменить на
IList<T>
и исправить любые ошибки компиляции:class FootballTeam : IList<FootballPlayer> { private List<FootballPlayer> Players { get; set; } override void Add(FootballPlayer player) { if (this.Players.Sum(p => p.Salary) + player.Salary > SALARY_CAP)) { throw new InvalidOperationException("Would exceed salary cap!"); } } /* boiler plate for rest of IList */ }
, но если вы публично выступили с третьим лицом, вы только что внесли изменения, которые могут привести к ошибкам компиляции и / или времени выполнения.
TL; DR - руководящие принципы для общедоступных API. Для частных API выполните то, что вы хотите.
Это работает на меня:
void RunWithRedirect(string cmdPath)
{
var proc = new Process();
proc.StartInfo.FileName = cmdPath;
// set up output redirection
proc.StartInfo.RedirectStandardOutput = true;
proc.StartInfo.RedirectStandardError = true;
proc.EnableRaisingEvents = true;
proc.StartInfo.CreateNoWindow = true;
// see below for output handler
proc.ErrorDataReceived += proc_DataReceived;
proc.OutputDataReceived += proc_DataReceived;
proc.Start();
proc.BeginErrorReadLine();
proc.BeginOutputReadLine();
proc.WaitForExit();
}
void proc_DataReceived(object sender, DataReceivedEventArgs e)
{
// output will be in string e.Data
}
Можно использовать следующий код
MemoryStream mem = new MemoryStream(1000);
StreamWriter writer = new StreamWriter(mem);
Console.SetOut(writer);
Assembly assembly = Assembly.LoadFrom(@"C:\ConsoleApp.exe");
assembly.EntryPoint.Invoke(null, null);
writer.Close();
string s = Encoding.Default.GetString(mem.ToArray());
mem.Close();