วิธีการห่อหุ้มตัวแปร 'ทั่วโลก' ใน C #? /ปฏิบัติที่ดีที่สุด


9

ใน C # วิธีที่ดีที่สุดสำหรับการห่อหุ้มตัวแปรที่ฉันต้องการใช้ในหลายวิธีคืออะไร? ตกลงไหมที่จะประกาศพวกเขาที่ชั้นบนสุดของชั้นเรียนของฉันเหนือสองวิธี?

นอกจากนี้หากฉันใช้การตั้งค่าแอพจากไฟล์ปรับแต่งฉันควรใช้ getter หรือไม่? แบบนี้...

private string mySetting{ get { return WebConfigurationManager.AppSettings["mySetting"]; } }

การปฏิบัติที่ดีที่สุดคืออะไร?


อะไรคือวัตถุประสงค์ของผู้ทะเยอทะยานนอกเหนือจากการเพิ่มเลเยอร์ทางอ้อม (และอาจไม่จำเป็น) เพิ่มเติม?
Robert Harvey

4
ผู้ทะเยอทะยานดีกว่าการโทรหลายสายWebConfigurationManager.AppSettingsเพราะสะดวกกว่าที่จะเปลี่ยนในภายหลัง
Daniel Little

@Lavinski: แน่นอนถ้าคุณคิดว่าคุณอาจเปลี่ยนที่เก็บข้อมูลสำหรับที่อื่นในภายหลัง ในทางปฏิบัตินั้นไม่ค่อยเกิดขึ้นและโอกาสที่มันจะเกิดขึ้นสำหรับ AppSettings ดูเหมือนจะเล็กไปหมด
Robert Harvey

10
"getter" มีข้อได้เปรียบที่ทำให้การทำงานของระบบ intellisense - และคุณมีสตริงคีย์ "mySetting" (ซึ่งไม่ถูกตรวจสอบโดยคอมไพเลอร์หากเขียนอย่างถูกต้อง) ในที่เดียวเท่านั้น
Doc Brown

คำตอบ:


5

มันไม่ได้เป็นเพียงแค่ตกลง อ้างอิงจากหนังสือ Clean Code ว่าจริง ๆ แล้วมันเป็นแนวปฏิบัติที่ดีมากและลุงบ็อบสนับสนุนมันอย่างแท้จริง ตัวแปรที่ใช้โดยวิธีการหลายวิธีสามารถแสดงการทำงานร่วมกันระดับสูงระหว่างวิธีต่างๆ ยิ่งไปกว่านั้นตัวแปรของวัตถุในระดับสูงอาจบอกเป็นนัยได้ว่าคลาสควรแบ่งออกเป็นสองส่วนดังนั้นการประกาศให้พวกเขาเป็นตัวแปรวัตถุสามารถช่วยคุณค้นหาผู้สมัครคลาสที่ซ่อนอยู่

ตัวแปรระดับวัตถุไม่ใช่ตัวแปรทั่วโลกดังนั้นอย่ากลัวที่จะใช้มันหากพวกเขาควรแบ่งปันด้วยวิธีการต่าง ๆ


ขอบคุณสำหรับความช่วยเหลือของคุณแม้ว่าฉันคิดว่าเมื่อคุณพูดว่าการทำงานร่วมกันคุณหมายถึงการมีเพศสัมพันธ์จริงๆ
user1944367

ไม่ฉันหมายถึงการทำงานร่วมกัน ในวิชาวิศวกรรมซอฟต์แวร์ฉันมีช่วงเวลาที่ยากลำบากในการเข้าใจถึงความปรารถนาในการทำงานร่วมกันสูง เรามักจะมีความต้องการทางเพศสัมพันธ์หลังจากมีเพศสัมพันธ์ต่ำและมีการเกาะกลุ่มสูง การแต่งงานกันเป็นเรื่องทางกายภาพที่เราสามารถมองเห็นได้ด้วยวิธีการของเราเอง หากคลาสใช้คลาสอื่นแสดงว่าเป็นคลาสนั้น ถ้ามันเป็นการยกตัวอย่างและวัตถุประสงค์ของคลาสที่กล่าวมาจริงๆ อย่างไรก็ตามการทำงานร่วมกันเป็นสิ่งที่มีเหตุผลมากขึ้น การทำงานร่วมกันสูงในชั้นเรียนหมายความว่าวิธีการเป็นของโดเมนที่คล้ายกันมากถึงแม้ว่าพวกเขาจะไม่แบ่งปันตัวแปรใด ๆ ระหว่างพวกเขา
Uri

วิธีการต่าง ๆ ที่ใช้ตัวแปรวัตถุนั้นไม่ได้หมายความว่าพวกมันจะอยู่คู่กัน ฉันสามารถมีคลาส Encrypter ด้วยตัวแปรรหัสผ่านถ่าน [] และมี Encrypt (ข้อความสตริง); และถอดรหัส (ข้อความสตริง); วิธีการภายใน ทั้งคู่ใช้ตัวแปรรหัสผ่านเดียวกัน แต่ไม่มีการเชื่อมต่อระหว่างกันอย่างชัดเจน อย่างไรก็ตามคุณอาจสังเกตเห็นว่าพวกเขาจัดการกับโดเมนเดียวกันและนั่นคือการเข้ารหัสข้อความ เท่าที่ฉันรู้พวกเขามีการทำงานร่วมกันในระดับสูงถึงแม้ว่าจะมีการแบ่งชั้นเรียนเป็นสองส่วนก็ตาม อาจมีการยืนยันว่าการเข้ารหัสไม่ได้อยู่ในโดเมนของการถอดรหัส
Uri

4

การห่อหุ้มการตั้งค่าของคุณในลักษณะที่คงที่เป็นความคิดที่ดี

สิ่งที่ฉันทำคือสร้างคลาสการตั้งค่าไม่ว่าจะเป็นคลาสสแตติกโกลบอลหนึ่งหรือหลายอินสแตนซ์ซึ่งฉันจะจัดการด้วยการฉีดพึ่งพา จากนั้นฉันโหลดการตั้งค่าทั้งหมดจากการกำหนดค่าลงในคลาสนั้นเมื่อเริ่มต้น

ฉันยังเขียนห้องสมุดเล็ก ๆ ที่ใช้การสะท้อนเพื่อทำให้ง่ายยิ่งขึ้น

เมื่อการตั้งค่าของฉันอยู่ในไฟล์กำหนดค่าของฉัน

<?xml version="1.0" encoding="utf-8" ?>
<configuration>   
    <appSettings>
        <add key="Domain" value="example.com" />
        <add key="PagingSize" value="30" />
        <add key="Invalid.C#.Identifier" value="test" />
    </appSettings>
</configuration>

ฉันสร้างคลาสแบบสแตติกหรืออินสแตนซ์ขึ้นอยู่กับความต้องการของฉัน สำหรับแอพพลิเคชั่นที่เรียบง่ายด้วยการตั้งค่าเพียงไม่กี่คลาสแบบคงที่หนึ่งก็ใช้ได้

private static class Settings
{
    public string Domain { get; set; }

    public int PagingSize { get; set; }

    [Named("Invalid.C#.Identifier")]
    public string ICID { get; set; }

}

แล้วใช้โทรห้องสมุดของฉันอย่างใดอย่างหนึ่งInflate.StaticหรือInflate.Instanceและสิ่งดีๆคือผมสามารถใช้แหล่งค่าใด ๆ ที่สำคัญ

using Fire.Configuration;

Inflate.Static( typeof(Settings), x => ConfigurationManager.AppSettings[x] );

รหัสทั้งหมดนี้อยู่ใน GitHub ที่https://github.com/Enexure/Enexure.Fire.Configuration

มีแม้กระทั่งแพ็คเกจ nuget:

PM> Install-Package Enexure.Fire.Configuration

รหัสสำหรับการอ้างอิง:

using System;
using System.Linq;
using System.Reflection;
using Fire.Extensions;

namespace Fire.Configuration
{
    public static class Inflate
    {
        public static void Static( Type type, Func<string, string> dictionary )
        {
            Fill( null, type, dictionary );
        }

        public static void Instance( object instance, Func<string, string> dictionary )
        {
            Fill( instance, instance.GetType(), dictionary );
        }


        private static void Fill( object instance, Type type, Func<string, string> dictionary ) 
        {

            PropertyInfo[] properties;
            if (instance == null) {

                // Static
                properties = type.GetProperties( BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly );
            } else {

                // Instance
                properties = type.GetProperties( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly );
            }

            // Get app settings and convert
            foreach (PropertyInfo property in properties) {
                var attributes = property.GetCustomAttributes( true );
                if (!attributes.Any( x => x is Ignore )) {

                    var named = attributes.FirstOrDefault( x => x is Named ) as Named;

                    var value = dictionary((named != null)? named.Name : property.Name);

                    object result;
                    if (ExtendConversion.ConvertTo(value, property.PropertyType, out result)) {
                        property.SetValue( instance, result, null );
                    }
                }
            }
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.