簡體   English   中英

將列表作為輸入參數的方法,其中每個項目都是不同的泛型類型

[英]Method that takes a list as input parameter where each item is a different generic type

注意:請在鎖定之前幫助我更好地格式化這個問題——我可能不夠精明,無法按照 StackOverflow 標准制定這個問題。 我將根據需要編輯帖子以進行澄清。

如何創建接收列表的方法,其中列表中的每個項目都屬於不同的泛型類型? 我已經嘗試了很多排列,但似乎找不到有效的方法。 我正在使用 OpenXml SDK 創建電子表格以在 Excel 中打開。 這個想法是創建一個單個文檔,該文檔接受具有 T 類型不同行數據的多個工作表作為配置。我的 api 看起來像這樣:

OpenXmlHelpers.Spreadsheet.CreateDocument(new ArrayList{
    new SheetConfig<Foo> { Name = "Foo sheet", RowData = ..., Columns = ...},
    new SheetConfig<Bar> { Name = "Bar sheet", RowData = ..., Columns = ...},
});

其中FooBar是我想在 Excel 文檔的每張紙上輸出為行數據的任何模型。 SheetConfig就像:

public class SheetConfig<T>
{
    /// <summary>
    /// Name of the sheet (shown in the tab)
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// Objects to display in the sheet
    /// </summary>
    public IList<T> RowData { get; set; }

    /// <summary>
    /// Field names to extract from the RowData and use as header names
    /// </summary>
    public List<ColumnConfig> Columns { get; set; }
}

ColumnConfig就像:

public class ColumnConfig
{
    /// <summary>
    /// Header text
    /// </summary>
    public string Title { get; set; }

    /// <summary>
    /// Object property to use under header
    /// </summary>
    public string FieldName { get; set; }
}

到目前為止,我的Spreadsheet類看起來像:

public class Spreadsheet
{
    public static void CreateDocument(IEnumerable<SheetConfig<T>> configs)
    {
        using (OpenXml.SpreadsheetDocument spreadsheetDocument = OpenXml.SpreadsheetDocument.Create("file.path.here", OpenXml.SpreadsheetDocumentType.Workbook))
        {
            // OpenXml stuff...
            OpenXml.Sheets sheets = new OpenXml.Sheets();

            foreach (var s in configs)
            {
                sheets.AppendChild(CreateSheet(s));
            }
        }
    }

    private static OpenXml.Sheet CreateSheet<T>(SheetConfig<T> config)
    {
        // OpenXML stuff...
        return new OpenXml.Sheet { Name = config.Name };
    }
}

第一個問題是它抱怨CreateDocument不像CreateDocument<T>並且我認為IEnumerable<SheetConfig<T>>輸入不完全正確,因為列表不是完全相同的類型T而是任意數量的類型,像FooBar

解決方案是確保所有模型類都有一個公共基類,我在下面的示例代碼中將其稱為ModelBase 這很像 Open XML SDK 中的OpenXmlElement類,它是 SDK 提供的所有強類型類的基類。

    public class ModelBase
    {
        private readonly Dictionary<string, object> _values = new Dictionary<string, object>();

        public object GetValue(string fieldName)
        {
            return _values.TryGetValue(fieldName, out object value) ? value : null;
        }

        public void SetValue(string fieldName, object value)
        {
            _values[fieldName] = value;
        }
    }

    public class Foo : ModelBase
    {
        public string First
        {
            get => (string) GetValue(nameof(First));
            set => SetValue(nameof(First), value);
        }

        public int Second
        {
            get => (int) GetValue(nameof(Second));
            set => SetValue(nameof(Second), value);
        }
    }

    public class Bar : ModelBase
    {
        public string One
        {
            get => (string)GetValue(nameof(One));
            set => SetValue(nameof(One), value);
        }

        public DateTime Two
        {
            get => (DateTime) GetValue(nameof(Two));
            set => SetValue(nameof(Two), value);
        }
    }

上面的示例代碼定義了兩個模型類FooBar ,它們都派生自ModelBase 后者還提供了由Dictionary<string, object>支持的“通用”getter 和 setter 方法,可用於按字段名稱存儲值。

根據上面的代碼,您將修改您的SheetConfig<T>如下所示,即通過添加約束where T : ModelBase

    public class SheetConfig<T> where T : ModelBase
    {
        /// <summary>
        /// Name of the sheet (shown in the tab)
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Objects to display in the sheet
        /// </summary>
        public IList<T> RowData { get; set; }

        /// <summary>
        /// Field names to extract from the RowData and use as header names
        /// </summary>
        public List<ColumnConfig> Columns { get; set; }
    }

    public class ColumnConfig
    {
        /// <summary>
        /// Header text
        /// </summary>
        public string Title { get; set; }

        /// <summary>
        /// Object property to use under header
        /// </summary>
        public string FieldName { get; set; }
    }

最后,您的代碼沒有編譯,因為您應該編寫CreateDocument<T>(...)而不是僅僅CreateDocument(...) 但是,不再需要 type 參數,因為您現在可以使用IEnumerable<SheetConfig<ModelBase>> configs作為形式參數。 總的來說, Spreadsheet類可以更改如下:

    public class Spreadsheet
    {
        public static void CreateDocument(IEnumerable<SheetConfig<ModelBase>> configs)
        {
            using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create("file.path.here", SpreadsheetDocumentType.Workbook))
            {
                // OpenXml stuff...
                var sheets = new Sheets();

                foreach (SheetConfig<ModelBase> s in configs)
                {
                    sheets.AppendChild(CreateSheet(s));
                }
            }
        }

        private static Sheet CreateSheet(SheetConfig<ModelBase> config)
        {
            // OpenXML stuff...
            return new Sheet { Name = config.Name };
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM