Проблемы с кодировкой с#

Рейтинг: -1Ответов: 1Опубликовано: 15.03.2023

Написал программу для реализации командной строки с помощью рефлексии.Программа написана кривовато(такое задание было),но дело в другом. Я запускаю команды с помощью процессов и возникает какая-то проблема с кодировкой.Но когда я ввожу только одну команду,такой проблемы не возникает. Скриншот вывода прикрепил 1

using System.Diagnostics;
using System.Reflection;
using System.Text.RegularExpressions;

[AttributeUsage(AttributeTargets.Method|AttributeTargets.Field|AttributeTargets.Property)]
public class CommandLineAttribute : Attribute
{
    public string CommandSwitch { get; set; }
    public CommandLineAttribute() {
        CommandSwitch = " ";
    }
    public CommandLineAttribute(string name)
    {
        this.CommandSwitch = name;
    }
 
}

class Commands
{
    [CommandLine] public bool IpConfig;
    [CommandLine] public bool GetMac;
    [CommandLine] public bool Netstat;
    [CommandLine] public string Pathping { get; set; }

    [CommandLine]
    public void ping(string address)
    {
        Process.Start("ping", address);
    }

    [CommandLine]
    public void tracert(string address)
    {

        Process.Start("tracert", address);
    }
}

class CMD
{
    public static T ParseCommandLine<T>(string[] args) where T : new()
    {
        Type type = typeof(T);
        T obj = new T();
        Console.OutputEncoding = System.Text.Encoding.UTF8;
        bool found = false;
        string command="";
        string value;

        var Members = type.GetMembers();

        for(int m = 0; m < args.Length;m++)
        {
          
            for (int i = 0; i < Members.Length; i++)
            {
              
                if (!args[m].Contains("="))
                {
                    command=args[m].Substring(1);
                    value = "true";
                }
                else 
                {
                    command = args[m].Substring(1, args[m].IndexOf('=') - 1);
                    value = args[m].Substring(args[m].IndexOf('=') + 1);
                }
             
           
                if (Members[i].Name == command)
                {
                    
                    found = true;
                    switch (Members[i].MemberType)
                    {
                        case MemberTypes.Field:
                            {
                              
                                FieldInfo field = Members[i] as FieldInfo;
                               
                                var fieldType = field.FieldType;
                                // Проверяем, входит ли тип поля в список допустимых для командной строки типов данных
                                if (fieldType == typeof(int) || fieldType == typeof(double) || fieldType == typeof(bool) || fieldType == typeof(string))
                                {
                                    Console.WriteLine("Type is valid");
                                }
                                else
                                {
                                    Console.WriteLine("Type isn't valid");
                                    break;
                                }

                                object convertedValue = null;
                                try
                                {
                                    // Пытаемся провести преобразование строкового представления значения параметра командной строки к типу данных поля
                                    convertedValue = Convert.ChangeType(value, fieldType);
                                }
                                catch (Exception ex)
                                {
                                    // Если такое преобразование невозможно, генерируем исключение InvalidCastException
                                    throw new InvalidCastException($"Cannot convert value '{value}' to type {fieldType.FullName}.", ex);
                                }

    // Используем рефлексию, чтобы присвоить значение преобразованного значения параметра полю объекта
    ((FieldInfo)Members[i]).SetValue(obj, convertedValue);
                                  Process.Start(field.Name);
                                break;
                            }
                            break;
                        case MemberTypes.Property:
                            {
                                
                                PropertyInfo property = Members[i] as PropertyInfo;
                                var propertyType = property.PropertyType;
                                if (propertyType == typeof(int) || propertyType == typeof(double) ||
                                    propertyType == typeof(bool) || propertyType == typeof(string))
                                {
                                    Console.WriteLine("Type is valid");
                                }
                                else
                                {
                                    Console.WriteLine("Type isn't valid");
                                }

                                object convertedValue = null;
                                try
                                {
                                    // Пытаемся провести преобразование строкового представления значения параметра командной строки к типу данных поля
                                    convertedValue = Convert.ChangeType(value, propertyType);
                                }
                                catch (Exception ex)
                                {
                                    // Если такое преобразование невозможно, генерируем исключение InvalidCastException
                                    throw new InvalidCastException($"Cannot convert value '{value}' to type {propertyType.FullName}.", ex);
                                }
                                if (!property.CanWrite)
                                {
                                    throw new InvalidOperationException();
                                }
                                property.SetValue(obj, convertedValue);
                                Process.Start(property.Name);
                            }
                            break;
                        case MemberTypes.Method:
                            {
                              
                                var methodInfo = type.GetMethod(command);

                                if (methodInfo == null)
                                {
                                    throw new InvalidOperationException($"Method {value} not found.");
                                }

                                var parameters = methodInfo.GetParameters();



                                if (parameters.Length != 1 || (parameters[0].ParameterType != typeof(int) && (parameters[0].ParameterType != typeof(double))
                                    && (parameters[0].ParameterType != typeof(bool)) && (parameters[0].ParameterType != typeof(string))))
                                {
                                    throw new InvalidOperationException($"Method {args[1]} must have exactly one parameter of valid type.");
                                }

                                object convertedValue = null;
                                try
                                {
                                    // Пытаемся провести преобразование строкового представления значения параметра командной строки к типу данных поля
                                    convertedValue = Convert.ChangeType(value, parameters[0].ParameterType);
                                }
                                catch (Exception ex)
                                {
                                    // Если такое преобразование невозможно, генерируем исключение InvalidCastException
                                    throw new InvalidCastException($"Cannot convert value '{value}' to type {parameters[0].ParameterType.FullName}.", ex);
                                }
                                methodInfo.Invoke(obj, new object[] { convertedValue });
                            }
                            break;
                    }
                }
            }

        }

        if (!found) throw new ArgumentException(String.Format("Command", command,"isn't found"), "num");

        return obj;
    }
}

class Program
{
    static void Main(string[] args)
    {

         CMD.ParseCommandLine<Commands>(new string[4] { "-ping=www.google.com", "-tracert=www.google.com", "-IpConfig","-Pathping" });
    }
}

Ответы

▲ 5Принят

Проблема не в кодировке, а в том что несколько запускаемых процессов вразнобой пишут данные в консоль. А так как кодировка у вас не однобайтовая, нарушается последовательность управляющих кодов и вывод в консоль разрушается.

Для того чтобы это побороть, надо избежать параллельного вывода в консоль.

Например так

Process.Start(field.Name).WaitForExit();

Пока процесс работает, ничего другого происходить не будет, и вывод не будет поломан.

Если же хочется выводить параллельно, но чтобы не ломался вывод, можно поступить следующим образом.

class ProcessWrapper
{
    private readonly Process process;

    public ProcessWrapper(ProcessStartInfo info) 
    {
        process = new Process();
        process.StartInfo = info;
        process.StartInfo.RedirectStandardOutput = true;
        process.StartInfo.RedirectStandardError = true;
        process.ErrorDataReceived += Process_ErrorDataReceived;
        process.OutputDataReceived += Process_OutputDataReceived;
    }

    private void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        Console.Write(e.Data);
    }

    private void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
    {
        Console.Write(e.Data);
    }

    public void Start()
    {
        process.Start();
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();
    }

    public void WaitForExit()
    {
        process.WaitForExit();
    }
}

И запускать так

var wrapper = new ProcessWrapper(new ProcessStartInfo(field.Name));
wrapper.Start();

Кстати, наличие строки Console.OutputEncoding = System.Text.Encoding.UTF8; необязательно.