C# 卡住创建自定义配置部分
C# Stuck Creating Custom Configuration Section
我第一次尝试实现自定义配置部分的创建,我感到非常沮丧。
举个例子,假设我想创建一个自定义部分来存储要由我的程序读取的 CSV 文件列表 - 每个文件,因此具有:
- 文件路径
- 一个分隔符
-
CsvColumn
的列表(另一种类型)
然后,每个 CsvColumn
可以具有如下属性:
- 文件中的名字
- 类型
(请忽略这是否适合通过配置完成,这只是给出层次结构的示例,因此我可以学习如何执行此操作)。
所以,我创建了以下配置文件:
<configSections>
<section name="CsvData" type="CSV_Loader.CsvData, CSV_Loader" />
</configSections>
<CsvData>
<CsvFiles>
<CsvFile Path="MyPath1" Delimiter=",">
<CsvColumn NameInFile="Col1" Type="System.String"/>
<CsvColumn NameInFile="Col2" Type="System.String"/>
<CsvColumn NameInFile="Col3" Type="System.Double"/>
</CsvFile>
<CsvFile Path="MyPath2" Delimiter=",">
<CsvColumn NameInFile="Col1" Type="System.String"/>
</CsvFile>
</CsvFiles>
</CsvData>
而且,现在我正在寻求根据给定 here 的示例/解决方案创建自定义 类,但遇到了严重的困难。我目前的代码大致如下:
Csv列:
public class CsvColumn : ConfigurationElement
{
[ConfigurationProperty("NameInFile", IsRequired = true, IsKey = true)]
public string NameInFile
{
get { return (string)this["NameInFile"]; }
}
[ConfigurationProperty("Type", IsRequired = true, DefaultValue = "")]
public string Type
{
get { return (string)this["Type"]; }
}
}
(仅供参考 - 我想将我的 Type
存储为实际的 Type
变量,但我将其设置为 String
以防那是我的问题所在)
Csv文件:
[ConfigurationCollection(typeof(CsvColumn), AddItemName = "CsvColumn", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class CsvFile : ConfigurationElementCollection
{
[ConfigurationProperty("Path", DefaultValue = "", IsKey = true, IsRequired = true)]
public string Path
{
get { return (string)(base["Path"]); }
}
[ConfigurationProperty("Delimiter", DefaultValue = ",", IsRequired = true)]
public string Delimiter
{
get { return (string)(base["Delimiter"]); }
}
public CsvColumn this[int index]
{
get { return (CsvColumn)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
public void Add(CsvColumn column)
{
BaseAdd(column);
}
public void Clear()
{
BaseClear();
}
protected override ConfigurationElement CreateNewElement()
{
return new CsvColumn();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((CsvColumn)element).NameInFile;
}
public void Remove(CsvColumn column)
{
BaseRemove(column.NameInFile);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(String name)
{
BaseRemove(name);
}
}
Csv文件集合:
[ConfigurationCollection(typeof(CsvFile), AddItemName = "CsvFile", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class CsvFiles : ConfigurationElementCollection
{
public CsvFile this[int index]
{
get { return (CsvFile)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
public void Add(CsvFile file)
{
BaseAdd(file);
}
public void Clear()
{
BaseClear();
}
protected override ConfigurationElement CreateNewElement()
{
return new CsvFile();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((CsvFile)element).Path;
}
public void Remove(CsvFile file)
{
BaseRemove(file.Path);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(String name)
{
BaseRemove(name);
}
}
CsvData:
public class CsvData : ConfigurationSection
{
[ConfigurationProperty("CsvFiles")]
public CsvFiles CsvFiles
{
get { return base["CsvFiles"] as CsvFiles; }
}
}
我正尝试在我的代码中调用它,如下所示:
var csvData = (ConfigurationManager.GetSection("CsvData") as CsvData);
但是我得到了 ConfigurationException
Unrecognized element 'CsvColumn'
。
我不知道为什么。
我的主要问题是:
- 我做错了什么?
- 是否有更简单的(通用)方法来实现此目的,使这个过程更容易?
非常感谢!!!
我不确定为什么会发生这种情况,大概是框架中的错误,但是当你有这些嵌套的 ConfigurationElementCollection
实例时,它似乎忽略了 AddItemName
位于内部集合的 ConfigurationCollection
属性上。您可以通过将 CsvColumn
元素更改为 add
元素来自己确认这一点,它会正确反序列化。
将以下构造函数添加到您的 CsvFile
class 应该可以解决您的问题:
public CsvFile()
{
AddElementName = "CsvColumn";
}
关于你的第二个问题,你试过图书馆吗CsvHelper
我第一次尝试实现自定义配置部分的创建,我感到非常沮丧。
举个例子,假设我想创建一个自定义部分来存储要由我的程序读取的 CSV 文件列表 - 每个文件,因此具有:
- 文件路径
- 一个分隔符
-
CsvColumn
的列表(另一种类型)
然后,每个 CsvColumn
可以具有如下属性:
- 文件中的名字
- 类型
(请忽略这是否适合通过配置完成,这只是给出层次结构的示例,因此我可以学习如何执行此操作)。
所以,我创建了以下配置文件:
<configSections>
<section name="CsvData" type="CSV_Loader.CsvData, CSV_Loader" />
</configSections>
<CsvData>
<CsvFiles>
<CsvFile Path="MyPath1" Delimiter=",">
<CsvColumn NameInFile="Col1" Type="System.String"/>
<CsvColumn NameInFile="Col2" Type="System.String"/>
<CsvColumn NameInFile="Col3" Type="System.Double"/>
</CsvFile>
<CsvFile Path="MyPath2" Delimiter=",">
<CsvColumn NameInFile="Col1" Type="System.String"/>
</CsvFile>
</CsvFiles>
</CsvData>
而且,现在我正在寻求根据给定 here 的示例/解决方案创建自定义 类,但遇到了严重的困难。我目前的代码大致如下:
Csv列:
public class CsvColumn : ConfigurationElement
{
[ConfigurationProperty("NameInFile", IsRequired = true, IsKey = true)]
public string NameInFile
{
get { return (string)this["NameInFile"]; }
}
[ConfigurationProperty("Type", IsRequired = true, DefaultValue = "")]
public string Type
{
get { return (string)this["Type"]; }
}
}
(仅供参考 - 我想将我的 Type
存储为实际的 Type
变量,但我将其设置为 String
以防那是我的问题所在)
Csv文件:
[ConfigurationCollection(typeof(CsvColumn), AddItemName = "CsvColumn", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class CsvFile : ConfigurationElementCollection
{
[ConfigurationProperty("Path", DefaultValue = "", IsKey = true, IsRequired = true)]
public string Path
{
get { return (string)(base["Path"]); }
}
[ConfigurationProperty("Delimiter", DefaultValue = ",", IsRequired = true)]
public string Delimiter
{
get { return (string)(base["Delimiter"]); }
}
public CsvColumn this[int index]
{
get { return (CsvColumn)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
public void Add(CsvColumn column)
{
BaseAdd(column);
}
public void Clear()
{
BaseClear();
}
protected override ConfigurationElement CreateNewElement()
{
return new CsvColumn();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((CsvColumn)element).NameInFile;
}
public void Remove(CsvColumn column)
{
BaseRemove(column.NameInFile);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(String name)
{
BaseRemove(name);
}
}
Csv文件集合:
[ConfigurationCollection(typeof(CsvFile), AddItemName = "CsvFile", CollectionType = ConfigurationElementCollectionType.BasicMap)]
public class CsvFiles : ConfigurationElementCollection
{
public CsvFile this[int index]
{
get { return (CsvFile)BaseGet(index); }
set
{
if (BaseGet(index) != null)
{
BaseRemoveAt(index);
}
BaseAdd(index, value);
}
}
public void Add(CsvFile file)
{
BaseAdd(file);
}
public void Clear()
{
BaseClear();
}
protected override ConfigurationElement CreateNewElement()
{
return new CsvFile();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((CsvFile)element).Path;
}
public void Remove(CsvFile file)
{
BaseRemove(file.Path);
}
public void RemoveAt(int index)
{
BaseRemoveAt(index);
}
public void Remove(String name)
{
BaseRemove(name);
}
}
CsvData:
public class CsvData : ConfigurationSection
{
[ConfigurationProperty("CsvFiles")]
public CsvFiles CsvFiles
{
get { return base["CsvFiles"] as CsvFiles; }
}
}
我正尝试在我的代码中调用它,如下所示:
var csvData = (ConfigurationManager.GetSection("CsvData") as CsvData);
但是我得到了 ConfigurationException
Unrecognized element 'CsvColumn'
。
我不知道为什么。
我的主要问题是:
- 我做错了什么?
- 是否有更简单的(通用)方法来实现此目的,使这个过程更容易?
非常感谢!!!
我不确定为什么会发生这种情况,大概是框架中的错误,但是当你有这些嵌套的 ConfigurationElementCollection
实例时,它似乎忽略了 AddItemName
位于内部集合的 ConfigurationCollection
属性上。您可以通过将 CsvColumn
元素更改为 add
元素来自己确认这一点,它会正确反序列化。
将以下构造函数添加到您的 CsvFile
class 应该可以解决您的问题:
public CsvFile()
{
AddElementName = "CsvColumn";
}
关于你的第二个问题,你试过图书馆吗CsvHelper