मैं थोड़ा प्रोग्रामिंग ज्ञान वाला एक परीक्षक हूं, लेकिन मैं इसे काम पर नहीं ला सकता।

मैं अपने एकीकरण परीक्षण (BaseIntegrationTest.cs) के लिए बेस क्लास बना रहा हूं। यह उन DbContext और Repository प्रकारों को स्वीकार करने के लिए जेनेरिक का उपयोग करता है जिन्हें विशेष परीक्षण वर्ग लक्षित कर रहा है। बेस क्लास डेटाबेस संदर्भ और कनेक्शन स्थापित करता है और उपयुक्त भंडार/नियंत्रक वर्गों के उदाहरण बनाता है।

    class BaseIntegrationTest <TContext, TRepo> where TContext : DbContext where TRepo : BaseRepository
    {
        ...

    }

DbContext और Repository प्रकारों के अलावा, जो प्रत्येक परीक्षण वर्ग के लिए संभावित रूप से अद्वितीय हैं, हमें लक्ष्य रिपोजिटरी वर्ग के लिए DatabaseConnectionString और कंस्ट्रक्टर के हस्ताक्षर भी निर्धारित करने होंगे (जैसे कि भेजे गए मापदंडों की संख्या कंस्ट्रक्टर भिन्न हो सकते हैं)।

मैं इन मूल्यों को पारित सामान्य प्रकारों के आधार पर निर्धारित करता हूं। TContext परिभाषित करता है कि मैं किस डीबीकनेक्शनस्ट्रिंग का उपयोग करता हूं, और TRepo परिभाषित करता है कि किस रिपोजिटरी कन्स्ट्रक्टर हस्ताक्षर का उपयोग करना है। इन चीजों को परिभाषित करने के लिए मैंने एक निजी स्थिर आंतरिक वर्ग GenericTypeHelper जोड़ा है। मेरी BaseIntegrationTest क्लास तो कुछ इस तरह दिखती है...

...

namespace OurProduct.Tests.IntegrationTests
{
    class BaseIntegrationTest <TContext, TRepo> where TContext : DbContext where TRepo : BaseRepository
    {
        ...

        protected Dictionary<string, string> LocalDbConfig = new Dictionary<string, string>();
        protected TRepo Repository;

        [OneTimeSetUp]
        public void SetUp()
        {
            DefineLocalDbConfigs();
            SetupNewLocalDB();
            Repository = SetupRepository<TContext, TRepo>();
        }

        [OneTimeTearDown]
        public void TearDown()
        {
            TearDownLocalDB();
        }

        private void DefineLocalDbConfigs()
        {
            ...
            // define LocalDbConfig dictionary and add db configs
            ...
        }

        private void SetupNewLocalDB()
        {
            ...
            // set up LocalDb databases
            ...
        }

        public RepoType SetupRepository<DbContextType, RepoType>() where DbContextType : DbContext where RepoType : BaseRepository
        {
            var configBuilder = new ConfigurationBuilder();
            configBuilder.AddInMemoryCollection(LocalDbConfig);
            var configuration = configBuilder.Build();

            var dbBuilder = new DbContextOptionsBuilder<DbContextType>();
            dbBuilder.UseSqlServer(configuration.GetConnectionString(GenericTypeHelper.DbConnStringForDbContext[typeof(DbContextType)]));

            var context = (DbContextType)Activator.CreateInstance(typeof(DbContextType), new object[] { dbBuilder.Options });
            var logger = Mock.Of<ILogger<RepoType>>();
            var clock = new SystemClock();

            var commonLogger = Mock.Of<ILogger<CommonRepository>>();
            var commonRepo = new CommonRepository(configuration, commonLogger, clock);

            var repoConstrParamObjArr = GenericTypeHelper.GetRepoConstrParamObjArr(context, logger, clock, commonRepo);
            return (RepoType)Activator.CreateInstance(typeof(RepoType), repoConstrParamObjArr);
        }

        private void TearDownLocalDB()
        {
            foreach (var dbConnDefn in LocalDbConfig)
            {
                ...
                // open, set offline, close, dispose database
                ...
            }
        }

        private static class GenericTypeHelper
        {
            internal static readonly Dictionary<Type, string> DbConnStringForDbContext = new Dictionary<Type, string>
            {
                { typeof(DataContextA), "DB1" },
                { typeof(DataContextB), "DB2" },
                { typeof(DataContextC), "DB3" },
                { typeof(DataContextD), "DB1" },
                { typeof(DataContextE), "DB2" },
                { typeof(DataContextF), "DB3" }
            };

            internal static object[] GetRepoConstrParamObjArr<DbContextType, RepoType>(
                    DbContextType context,
                    ILogger<RepoType> logger,
                    SystemClock clock,
                    CommonRepository commonRepo)
                        where DbContextType : DbContext 
                        where RepoType : BaseRepository
                => typeof(RepoType) switch
                {
                    // these give compile error... CS0150: A constant value is expected
                    typeof(DataRepositoryA) => new object[] { context, logger, clock, commonRepo },
                    typeof(DataRepositoryB) => new object[] { context, logger, clock },
                    // these give compile error... CS8121: An expression of type 'Type' cannot be handled by a pattern of type 'DataRepositoryC'
                    DataRepositoryC         => new object[] { context, logger, clock, commonRepo },
                    DataRepositoryD         => new object[] { context, logger, clock },
                    _ => new object[] { }
                };

        }

    }
}

यह आंतरिक वर्ग मुझे संकलन त्रुटियां देता है (जैसा कि टिप्पणियों में उल्लेख किया गया है) जहां मैं जेनेरिक RepoType की तुलना सूचीबद्ध संभावित रिपोजिटरी वर्ग प्रकारों से करने के लिए स्विच स्टेटमेंट का उपयोग करने का प्रयास करता हूं और BaseIntegrationTest में पारित किया जाएगा। क्या कोई तरीका है जिससे मैं सामान्य प्रकार से मेल खाने के लिए क्लीन स्विच कार्यक्षमता का उपयोग कर सकता हूं?

0
Drew 4 पद 2020, 12:37

1 उत्तर

सबसे बढ़िया उत्तर

जबकि @ मैथ्यू वाटसन का जवाब (@ द जनरल की मदद से) चतुर था और इसने मेरे संकलन के मुद्दों को हल किया, यह वांछित के रूप में नहीं चला। default(RepoType) मूल प्रकारों के लिए सही प्रकार का अपेक्षित डिफ़ॉल्ट मान देता है, हालांकि गैर-मूल प्रकारों के लिए यह null देता है। इसका मतलब है कि स्विच स्टेटमेंट डिफ़ॉल्ट _ => new object[] { } पर मेल खाता है, भले ही RepoType मैं सामान्य रूप से पास हो।

हालाँकि मुझे nameof() के उपयोग के माध्यम से एक समाधान मिला जो मेरी आवश्यकताओं के अनुरूप है।

मूल कोड मुझे संकलन त्रुटियां दे रहा है ...

    internal static object[] GetRepoConstrParamObjArr<DbContextType, RepoType>(
            DbContextType context,
            ILogger<RepoType> logger,
            SystemClock clock,
            CommonRepository commonRepo)
                where DbContextType : DbContext 
                where RepoType : BaseRepository
        => typeof(RepoType) switch
        {
            // these give compile error... CS0150: A constant value is expected
            typeof(DataRepositoryA) => new object[] { context, logger, clock, commonRepo },
            typeof(DataRepositoryB) => new object[] { context, logger, clock },
            // these give compile error... CS8121: An expression of type 'Type' cannot be handled by a pattern of type 'DataRepositoryC'
            DataRepositoryC         => new object[] { context, logger, clock, commonRepo },
            DataRepositoryD         => new object[] { context, logger, clock },
            _ => new object[] { }
        };

समाधान जो अपेक्षित रूप से संकलित और चलता है ...

    internal static object[] GetRepoConstrParamObjArr<DbContextType, RepoType>(
            DbContextType context,
            ILogger<RepoType> logger,
            SystemClock clock,
            CommonRepository commonRepo)
                where DbContextType : DbContext 
                where RepoType : BaseRepository
        => typeof(RepoType).Name switch
        {
            nameof(DataRepositoryA) => new object[] { context, logger, clock, commonRepo },
            nameof(DataRepositoryB) => new object[] { context, logger, clock },
            nameof(DataRepositoryC) => new object[] { context, logger, clock, commonRepo },
            nameof(DataRepositoryD) => new object[] { context, logger, clock },
            _                       => new object[] { }
        };

1
Drew 6 पद 2020, 01:06