0

在我的代码中,我有 3 个部分,但是在 3 个部分中的 2 个部分中,代码几乎相同,我想知道是否有人可以帮助我正确地构造它们,这样我只需要在一个范围内编写一次,以便它可以两个部分都可以看到,所以我不需要那么多代码。(框架 3.5)

public static void FakeDriveInfo()
{
    List<DriveInfo> driveList = DriveInfo.GetDrives().Where(x => x.IsReady).ToList<DriveInfo>();

    Server server = new Server();

    Console.WriteLine();
    Console.ForegroundColor = ConsoleColor.White;
    Console.WriteLine("Server ID :      {0}", server.ServerID = 0);
    Console.WriteLine("Server Name :    {0}", server.ServerName = string.Concat(System.Environment.MachineName));
    Console.WriteLine();

    for (int i = 0; i < driveList.Count; i++)
    {
        ServerDrive serverDrives = new ServerDrive();

        Console.WriteLine("Drive Letter:    {0}", driveList[i].Name);
        Console.WriteLine("Total Size:      {0}", FormatBytes(driveList[i].TotalSize));
        Console.WriteLine("Volume Label:    {0}", driveList[i].VolumeLabel);
        Console.WriteLine("Free Space:      {0}", FormatBytes(driveList[i].TotalFreeSpace));
        Console.WriteLine("Drive Format:    {0}", driveList[i].DriveFormat);
        Console.ReadLine();
    }
}

public static void RealDriveInfo()
{
    //Create the server object - You will need create a list of the server objects.
    Server server = new Server();

    //Get all drives information
    List<DriveInfo> driveList = DriveInfo.GetDrives().Where(x => x.IsReady).ToList<DriveInfo>();

    //Insert information of one server - You will need get information of all servers
    server.ServerID = 0; //Here is necessery put PK key. I recommend doing the SQL server will automatically generate the PK.
    server.ServerName = string.Concat(System.Environment.MachineName);

    //Inserts information in the newServers object
    for (int i = 0; i < driveList.Count; i++)
    {
        ServerDrive serverDrives = new ServerDrive();

        //Put here all the information to obeject Server                
        serverDrives.DriveLetter = driveList[i].Name;
        serverDrives.TotalSpace = driveList[i].TotalSize;
        serverDrives.DriveLabel = driveList[i].VolumeLabel;
        serverDrives.FreeSpace = driveList[i].TotalFreeSpace;
        serverDrives.DriveType = driveList[i].DriveFormat;

        //      server.ListServerDrives.Add(serverDrives);
        server.ServerDrives.Add(serverDrives);
    }

    //Add the information to an SQL Database using Linq.
    DataClasses1DataContext db = new DataClasses1DataContext(@"sqlserver");
    //   db.Servers.InsertAllOnSubmit(server);
    db.Servers.InsertOnSubmit(server);
    db.SubmitChanges();
}

我想要做的是将代码底部的 SQL to Linq 部分移到它自己的部分中。但要做到这一点,我也必须拥有整个RealDriveInfo部分..

我想做的另一部分是制作它,List<DriveInfo> driveList = DriveInfo.GetDrives().Where(x=>x.IsReady).ToList<DriveInfo>();以便 FakeDriveInfo 和 RealDriveInfo 可以看到它。

任何反馈将不胜感激,谢谢。

EDIT : At the moment I am calling two methods, FakeDriveInfo(); = Executing the console app and showing me the info it is going to submit. Name, Letter, Label, Server Name, ID, etc. RealDriveInfo(); = Connecting to the SQL Server and inserting the information into the two tables.

I want to have a third method WriteInToDB(); = The DB Writing code would be taken from the RealDriveInfo Method and moved here instead.

At the moment I have two methods that practically look identical due to the scope. I want the scope shifted so that I can put the List part of the code into the Main() Method and both FakeDriveInfo and RealDriveInfo can use it from there instead of having the code duplicated.

Hopefully this adds a bit more sense to it all :)

4

4 回答 4

2

Create a method:

public static List<DriveInfo> GetDrives {
    return DriveInfo.GetDrives().Where(x => x.IsReady).ToList<DriveInfo>();
}

Call it in both places:

public static void FakeDriveInfo()
{
    List<DriveInfo> driveList = GetDrives();
    // ...
}

public static void RealDriveInfo()
{
    List<DriveInfo> driveList = GetDrives();
    // ....
}

This is one of the basic Refactorings. It's called Extract Method and has been described by Martin Fowler over here.

于 2012-08-07T13:35:53.107 回答
1

I hope I captured your functionality correctly. 3 regions, create, output, persist. You can ofcourse take each section and create reusable methods. You can move the output section to the ToString() method of Server.

        #region create graph

        var server = new Server()
        {
            ServerID = 0,
            ServerName = string.Concat(Environment.MachineName),
            ServerDrives = DriveInfo.GetDrives()
                                    .Where(x => x.IsReady)
                                    .Select(di => new ServerDrive()
                                    {
                                        DriveLetter = di.Name,
                                        TotalSpace = di.TotalSize,
                                        DriveLabel = di.VolumeLabel,
                                        FreeSpace = di.TotalFreeSpace,
                                        DriveType = di.DriveFormat
                                    })
                                    .ToList()
        };

        #endregion

        #region output graph

        Console.WriteLine();
        Console.ForegroundColor = ConsoleColor.White;
        Console.WriteLine("Server ID :      {0}", server.ServerID);
        Console.WriteLine("Server Name :    {0}", server.ServerName);
        Console.WriteLine();

        server.ServerDrives.ForEach(sd =>
        {
            Console.WriteLine("Drive Letter:    {0}", sd.DriveLetter);
            Console.WriteLine("Total Size:      {0}", sd.TotalSpace);
            Console.WriteLine("Volume Label:    {0}", sd.DriveLabel);
            Console.WriteLine("Free Space:      {0}", sd.FreeSpace);
            Console.WriteLine("Drive Format:    {0}", sd.DriveType);
            Console.ReadLine();
        });

        #endregion

        #region persist graph

        DataClasses1DataContext db = new DataClasses1DataContext(@"sqlserver");
        db.Servers.InsertOnSubmit(server);
        db.SubmitChanges();

        #endregion
于 2012-08-07T13:31:54.487 回答
1

I've taken the approach of creating a new method, ProcessDriveInfo, which is called by your two original methods. These two methods fetched a list of drives, created a server, did something with the server, and did something for each drive. I moved the first two steps into the ProcessDriveInfo, and passed in actions for the last two steps.

The first action (i.e. method) does something with the server, and the second action does something for a single driveInfo.

n.b. I've "answered" the question in that it removes the duplication, but it could be argued that it is less readable.

    public Server ProcessDriveInfo(Action<Server> initialAction, Action<Server, DriveInfo> driveInfoAction)
    {
        var driveList = DriveInfo.GetDrives().Where(x => x.IsReady).ToList();
        var server = new Server();

        initialAction(server);
        driveList.ForEach(dl => driveInfoAction(server, dl));

        return server;
    }

    public void FakeDriveInfo()
    {
        ProcessDriveInfo(WriteServerToConsole, WriteDriveInfoToConsole);
    }

    private void WriteServerToConsole(Server server)
    {
        Console.WriteLine();
        Console.ForegroundColor = ConsoleColor.White;
        Console.WriteLine("Server ID :      {0}", server.ServerID = 0);
        Console.WriteLine("Server Name :    {0}", server.ServerName = string.Concat(System.Environment.MachineName));
        Console.WriteLine();
    }

    private void WriteDriveInfoToConsole(Server server, DriveInfo t)
    {
        Console.WriteLine("Drive Letter:    {0}", t.Name);
        Console.WriteLine("Total Size:      {0}", FormatBytes(t.TotalSize));
        Console.WriteLine("Volume Label:    {0}", t.VolumeLabel);
        Console.WriteLine("Free Space:      {0}", FormatBytes(t.TotalFreeSpace));
        Console.WriteLine("Drive Format:    {0}", t.DriveFormat);
        Console.ReadLine();
    }

    public void RealDriveInfo()
    {
        var server = ProcessDriveInfo(InitialiseServer, WriteDriveInfoToServer);

        //Add the information to an SQL Database using Linq.
        var db = new DataClasses1DataContext(@"sqlserver");
        //   db.Servers.InsertAllOnSubmit(server);
        db.Servers.InsertOnSubmit(server);
        db.SubmitChanges();
    }

    private static void InitialiseServer(Server server)
    {
        // Insert information of one server - You will need get information of all servers
        server.ServerID = 0;
        // Here is necessery put PK key. I recommend doing the SQL server will automatically generate the PK.
        server.ServerName = Environment.MachineName;
    }

    private static void WriteDriveInfoToServer(Server server, DriveInfo t)
    {
        var serverDrives = new ServerDrive
                               {
                                   DriveLetter = t.Name,
                                   TotalSpace = t.TotalSize,
                                   DriveLabel = t.VolumeLabel,
                                   FreeSpace = t.TotalFreeSpace,
                                   DriveType = t.DriveFormat
                               };

        server.ServerDrives.Add(serverDrives);
    }
于 2012-08-07T13:39:21.580 回答
0

After pain-stakeingly realising, the answer was in method and class scope..

Just incase anyone would like to see what I did ::

public class Program
{
    List<DriveInfo> driveList = DriveInfo.GetDrives().Where(x => x.IsReady).ToList<DriveInfo>(); //Get all the drive info
    Server server = new Server();  //Create  the server object
    ServerDrive serverDrives = new ServerDrive();

    public void Main()
    {
        Program c = new Program();
        c.FakeDriveInfo();
        c.RealDriveInfo();
        c.WriteInToDB();
    }

    public static string FormatBytes(long bytes)
    {
        const int scale = 1024;
        string[] orders = new string[] { "GB", "MB", "KB", "Bytes" };
        long max = (long)Math.Pow(scale, orders.Length - 1);
        foreach (string order in orders)
        {
            if (bytes > max)
            {
                return string.Format("{0:##.##} {1}", Decimal.Divide(bytes, max), order);
            }

            max /= scale;
        }
        return "0 Bytes";
    }

    public void FakeDriveInfo()
        {

            Console.WriteLine();
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("Server ID :      {0}", server.ServerID = 0);
            Console.WriteLine("Server Name :    {0}", server.ServerName = string.Concat(System.Environment.MachineName));
            Console.WriteLine();


            for (int i = 0; i < driveList.Count; i++)
            {

                Console.WriteLine("Drive Letter:    {0}", driveList[i].Name);
                Console.WriteLine("Total Size:      {0}", FormatBytes(driveList[i].TotalSize));
                Console.WriteLine("Volume Label:    {0}", driveList[i].VolumeLabel);
                Console.WriteLine("Free Space:      {0}", FormatBytes(driveList[i].TotalFreeSpace));
                Console.WriteLine("Drive Format:    {0}", driveList[i].DriveFormat);
                Console.ReadLine();
            }
        }

    public void RealDriveInfo()
         {


            //Insert information of one server - You will need get information of all servers
            server.ServerID = 0; //Here is necessery put PK key. I recommend doing the SQL server will automatically generate the PK.
            server.ServerName = string.Concat(System.Environment.MachineName);

            //Inserts information in the newServers object
            for (int i = 0; i < driveList.Count; i++)
            {

                //Put here all the information to obeject Server                
                serverDrives.DriveLetter = driveList[i].Name;
                serverDrives.TotalSpace = driveList[i].TotalSize;
                serverDrives.DriveLabel = driveList[i].VolumeLabel;
                serverDrives.FreeSpace = driveList[i].TotalFreeSpace;
                serverDrives.DriveType = driveList[i].DriveFormat;
                server.ServerDrives.Add(serverDrives);

            }
         }

    public void WriteInToDB()
    {
        //Add the information to an SQL Database using Linq.
        DataClasses1DataContext db = new DataClasses1DataContext(@"cspsqldev");
        //   db.Servers.InsertAllOnSubmit(server);
        db.Servers.InsertOnSubmit(server);
        db.SubmitChanges();
    }

Simply by moving the parts I wanted to be seen by all methods, into the Class scope it now works.

Thanks for your feedback guys :)

于 2012-08-08T11:49:12.840 回答