사용자 정의 설정을 통해 플러그인 디자인을 실현하다
사용자 정의 설정을 거의 사용하지 않을 수도 있습니다. 아마도 사용자 정의 설정은 App Setting에만 한정되어 있을 것입니다. 그러나 시스템 설정에 대해서만 이해해야 할 것 같습니다.Configuration이라는 이름 공간 아래의 몇 가지 기본적인 유형은 기본적으로 알고 있습니다.예를 들어 ConfigurationSection, ConfigurationElement, ConfigurationElementCollection 등이다.이 기사는 System에 대해 소개하지 않습니다.Configuration의 기초 지식은 간단한 예를 통해 이른바 고급 지식점, 예를 들어 식별할 수 없는 설정 요소의 동적 해석 등을 설명한다.(소스 코드는 여기서 다운로드)
디렉터리 1, 사용자 정의 설정을 통해 이루어진 최종 효과 2, 관련 설정 유형의 정의 3, 두 가지 중요한 유형: NameTypeConfiguration Element과 NameTypeConfiguration Element CollectionT 4, ResourceProvider Factory의 정의 5, 보충
1. 사용자 정의 설정을 통해 이루어진 최종 효과
사용자 정의 설정의 역할에 대한 깊은 이미지를 만들기 위해 간단한 예를 보여 드리겠습니다..NET의 자원은.resx 파일에 국한되지 않습니다. 임의의 저장 형식에 소개된 사용자 정의 ResourceManager를 사용하면 다양한 자원 저장 형식에 대한 지원을 실현할 수 있습니다.현재 자원과의 읽기만 주목하고 우리는 서로 다른 저장 형식의 자원 읽기 조작을 바탕으로 해당하는 ResourceProovider에서 다음과 같은 간단한 IResourceProvider 인터페이스를 실현할 것이다.
1
:
public
interface
IResourceProvider
2
: {
3
:
object
GetObject(
string
key);
4
: }
그리고 우리는 두 개의 구체적인 ResourceProvider: DbResourceProvider와 XmlResourceProvider를 만들었는데 각각 데이터베이스 테이블과 XML 파일의 자원 저장 형식을 바탕으로 한다.DbResourceProvider는 데이터베이스에 연결되고 설정된 연결 문자열을 인용해야 하기 때문에 ConnectionStringName 속성이 있습니다.XmlResourceProvider는 파일 경로를 나타내는 특정 XML 파일에 액세스해야 합니다. FileName 속성은 파일 경로를 나타냅니다.
1
: [ConfigurationElementType(
typeof
(DbResourceProviderConfigurationElement))]
2
:
public
class
DbResourceProvider : IResourceProvider
3
: {
4
:
public
string
ConnnectionStringName {
get
;
private
set
; }
5
:
public
DbResourceProvider(
string
connectionStringName)
6
: {
7
:
this
.ConnnectionStringName
=
connectionStringName;
8
: }
9
:
public
object
GetObject(
string
key)
10
: {
11
:
throw
new
NotImplementedException();
12
: }
13
:
public
override
string
ToString()
14
: {
15
:
return
string
.Format(
"
{0}
\tConncectionString Name:{1}
"
,
typeof
(DbResourceProvider).FullName,
this
.ConnnectionStringName);
16
: }
17
: }
18
:
19
: [ConfigurationElementType(
typeof
(XmlResourceProviderConfigurationElement))]
20
:
public
class
XmlResourceProvider : IResourceProvider
21
: {
22
:
public
string
FileName {
get
;
private
set
; }
23
:
public
XmlResourceProvider(
string
fileName)
24
: {
25
:
this
.FileName
=
fileName;
26
: }
27
:
public
object
GetObject(
string
key)
28
: {
29
:
throw
new
NotImplementedException();
30
: }
31
:
public
override
string
ToString()
32
: {
33
:
return
string
.Format(
"
{0}
\tFile Name:{1}
"
,
typeof
(XmlResourceProvider).FullName,
this
.FileName);
34
: }
35
: }
어떤 ResourceProvider를 사용할지 구성을 통해 결정됩니다.전체 구성은artech에 정의됩니다.resources 프로필에서, 이 프로필은providers 서브 노드를 가지고 있으며, 일련의 ResourceProvider 목록을 정의합니다.모든 ResourceProvider 설정은 두 가지 같은 속성을 가지고 있습니다: Name과 Type, 그리고 자신만의 설정 속성 (예를 들어 DbResourceProvider의connectionStringName, XmlResourceProvider의 fileName).기본적으로 어떤 Provider를 사용할지 설정절의defaultProvider 속성을 통해 결정합니다.이 예에서는 기본적으로 DbProvider를 사용합니다.
1
:
?
xml version
=
"
1.0
"
encoding
=
"
utf-8
"
?
2
: configuration
3
: configSections
4
: section name
=
"
artech.resources
"
type
=
"
Artech.Resources.Configuration.ResourceSettings,Artech.CustomConfiguration
"
/
5
:
/
configSections
6
: artech.resources defaultProvider
=
"
DbProvider
"
7
: providers
8
: add name
=
"
DbProvider
"
type
=
"
Artech.Resources.DbResourceProvider, Artech.CustomConfiguration
"
connectionStringName
=
"
LocalSqlServer
"
/
9
: add name
=
"
XmlProvider
"
type
=
"
Artech.Resources.XmlResourceProvider, Artech.CustomConfiguration
"
fileName
=
"
C:\resources.xml
"
/
10
:
/
providers
11
:
/
artech.resources
12
:
/
configuration
현재 ResourceProviderFactory의 공장 클래스가 있습니다. 설정에 따라 기본 ResourceProvider를 만들거나 지정한 이름의 ResourceProvider를 만들 수 있습니다.이제 ResourceProviderFactory는 다음과 같은 방법으로 사용됩니다.
1
:
static
void
Main(
string
[] args)
2
: {
3
: IResourceProvider resourceProvider
=
ResourceProviderFactory.GetResourceProvider();
4
: Console.WriteLine(resourceProvider);
5
: Console.WriteLine();
6
:
7
: resourceProvider
=
ResourceProviderFactory.GetResourceProvider(
"
XmlProvider
"
);
8
: Console.WriteLine(resourceProvider);
9
: Console.WriteLine();
10
:
11
: resourceProvider
=
ResourceProviderFactory.GetResourceProvider(
"
DbProvider
"
);
12
: Console.WriteLine(resourceProvider);
13
: Console.WriteLine();
14
: }
결과 출력:
1
: Artech.Resources.DbResourceProvider
2
: ConncectionString Name:LocalSqlServer
3
:
4
: Artech.Resources.XmlResourceProvider
5
: File Name:C:\resources.xml
6
:
7
: Artech.Resources.DbResourceProvider
8
: ConncectionString Name:LocalSqlServer
다음은 전체 설정 체계와 ResourceProviderFactory의 실현을 소개합니다.
2. 관련 구성 유형의 정의
이제 설정과 관련된 유형의 정의를 살펴봅시다.전체 구성 섹션은 ConfigurationSection에서 직접 상속되는 다음과 같은 ResourceSettings 클래스로 정의됩니다.ResourceSettings는 두 가지 설정 속성을 가지고 있는데 그것이 바로DefaultProvider와Providers이다. 각각artech를 대표한다.resources의defaultProvider 속성과providers 하위 노드입니다.
1
:
public
class
ResourceSettings: ConfigurationSection
2
: {
3
: [ConfigurationProperty(
"
defaultProvider
"
, IsRequired
=
true
)]
4
:
public
string
DefaultProvider
5
: {
6
:
get
{
return
(
string
)
this
[
"
defaultProvider
"
];}
7
:
set
{
this
[
"
defaultProvider
"
]
=
value;}
8
: }
9
: [ConfigurationProperty(
"
providers
"
, IsRequired
=
true
)]
10
:
public
NameTypeElementCollectionResourceProviderConfigurationElement Providers
11
: {
12
:
get
{
return
(NameTypeElementCollectionResourceProviderConfigurationElement)
this
[
"
providers
"
];}
13
:
set
{
this
[
"
providers
"
]
=
value;}
14
: }
15
:
public
static
ResourceSettings GetConfiguration()
16
: {
17
:
return
(ResourceSettings)ConfigurationManager.GetSection(
"
artech.resources
"
);
18
: }
19
: }
속성Providers는 NameTypeElementCollectionT라는 일반 유형입니다.이름에서 알 수 있듯이 이것은 설정된 ResourceProvider 집합을 대표하는 집합 유형입니다.ResourceProvider 기반 구성 정의는 다음과 같은 ResourceProvider Configuration Element 추상 클래스에 있습니다.이 클래스는 사용자가 정의한 NameType Configuration Element 유형을 계승하고, 해당하는 ResourceProvider를 만드는 데 사용되는CreateProvider 추상적인 방법이 있습니다.
1
:
public
abstract
class
ResourceProviderConfigurationElement: NameTypeConfigurationElement
2
: {
3
:
public
abstract
IResourceProvider CreateProvider();
4
: }
DbResourceProvider와 XmlResourceProvider는 각각의 ResourceProviderConfigurationElement을 가지고 있는데 각각 DbResourceProviderConfigurationElement과 XmlResourceProviderConfigurationElement이다.
1
:
public
class
DbResourceProviderConfigurationElement : ResourceProviderConfigurationElement
2
: {
3
: [ConfigurationProperty(
"
connectionStringName
"
, IsRequired
=
true
)]
4
:
public
string
ConnectionStringName
5
: {
6
:
get
{
return
(
string
)
this
[
"
connectionStringName
"
];}
7
:
set
{
this
[
"
connectionStringName
"
]
=
value;}
8
: }
9
:
public
override
IResourceProvider CreateProvider()
10
: {
11
:
return
new
DbResourceProvider(
this
.ConnectionStringName);
12
: }
13
: }
14
:
15
:
public
class
XmlResourceProviderConfigurationElement : ResourceProviderConfigurationElement
16
: {
17
: [ConfigurationProperty(
"
fileName
"
, IsRequired
=
true
)]
18
:
public
string
FileName
19
: {
20
:
get
{
return
(
string
)
this
[
"
fileName
"
];}
21
:
set
{
this
[
"
fileName
"
]
=
value;}
22
: }
23
:
public
override
IResourceProvider CreateProvider()
24
: {
25
:
return
new
XmlResourceProvider(
this
.FileName);
26
: }
27
: }
세 가지 중요한 유형:NameTypeConfigurationElement과NameTypeConfigurationElementCollectionT
다음은 두 가지 중요한 유형을 소개하는데 첫 번째는 ResourceProviderConfigurationElement의 기본 클래스인 NameTypeConfigurationElement이다.말 그대로 NameType Configuration Element은 다음과 같은 두 가지 기본 구성 속성Name과 Type이 있는 구성 요소(Configuration Element)입니다.방법DeserializeElement는 비식별 설정 항목의 반서열화 문제를 해결하는 데 사용되는 것을 정의합니다.
1
:
public
class
NameTypeConfigurationElement : ConfigurationElement
2
: {
3
: [ConfigurationProperty(
"
name
"
, IsRequired
=
true
, IsKey
=
true
)]
4
:
public
string
Name
5
: {
6
:
get
{
return
(
string
)
this
[
"
name
"
];}
7
:
set
{
this
[
"
name
"
]
=
value;}
8
: }
9
: [ConfigurationProperty(
"
type
"
, IsRequired
=
true
)]
10
:
public
string
TypeName
11
: {
12
:
get
{
return
(
string
)
this
[
"
type
"
];}
13
:
set
{
this
[
"
type
"
]
=
value;}
14
: }
15
:
public
Type Type
16
: {
17
:
get
{
return
Type.GetType(
this
.TypeName);}
18
: }
19
:
public
void
DeserializeElement(XmlReader reader)
20
: {
21
:
base
.DeserializeElement(reader,
false
);
22
: }
23
: }
또 다른 유형은 NameType Configuration Element의 설정 요소 집합(Configuration Element Collection): NameType Element CollectionT입니다.전체 배치 체계의 핵심이라고 할 수 있는데 그 전체 정의는 다음과 같다.
1
:
public
class
NameTypeElementCollectionT : ConfigurationElementCollection
where
T : NameTypeConfigurationElement
2
: {
3
:
protected
override
ConfigurationElement CreateNewElement()
4
: {
5
:
return
Activator.CreateInstanceT();
6
: }
7
:
protected
override
object
GetElementKey(ConfigurationElement element)
8
: {
9
:
return
(element
as
NameTypeConfigurationElement).Name;
10
: }
11
:
protected
virtual
Type RetrieveConfigurationElementType(XmlReader reader)
12
: {
13
: Type configurationElementType
=
null
;
14
:
if
(reader.AttributeCount
0
)
15
: {
16
:
for
(
bool
go
=
reader.MoveToFirstAttribute(); go; go
=
reader.MoveToNextAttribute())
17
: {
18
:
if
(
"
type
"
.Equals(reader.Name))
19
: {
20
: Type providerType
=
Type.GetType(reader.Value,
false
);
21
: Attribute attribute
=
Attribute.GetCustomAttribute(providerType,
typeof
(ConfigurationElementTypeAttribute));
22
:
if
(attribute
==
null
)
23
: {
24
:
throw
new
ConfigurationErrorsException(
"
No ConfigurationElementTypeAttribute is applied.
"
);
25
: }
26
: configurationElementType
=
((ConfigurationElementTypeAttribute)attribute).ConfigurationElementType;
27
:
break
;
28
: }
29
: }
30
: reader.MoveToElement();
31
: }
32
:
return
configurationElementType;
33
: }
34
:
protected
override
bool
OnDeserializeUnrecognizedElement(
string
elementName, XmlReader reader)
35
: {
36
:
if
(
base
.AddElementName.Equals(elementName))
37
: {
38
: Type configurationElementType
=
this
.RetrieveConfigurationElementType(reader);
39
: var currentElement
=
(T)Activator.CreateInstance(configurationElementType);
40
: currentElement.DeserializeElement(reader);
41
:
base
.BaseAdd(currentElement,
true
);
42
:
return
true
;
43
: }
44
:
return
base
.OnDeserializeUnrecognizedElement(elementName, reader);
45
: }
46
:
public
T GetConfigurationElement(
string
name)
47
: {
48
:
return
(T)
this
.BaseGet(name);
49
: }
50
: }
설정에 대해 우리는 다음과 같은 인식을 가져야 한다. 우리는 상응하는 유형을 통해 설정 파일의 어떤 XML 요소를 정의하는데, 읽을 때 실제로는 반서열화된 작업이다.한편, 성공적으로 서열화와 반서열화에 대해 그 근본적인 전제는 목표 유형을 확정하는 것이다. 왜냐하면 유형이 메타데이터를 묘사했기 때문이다.이 결론을 가지고 다시 XML로 표시된 설정과 ResourceSettings의 정의를 보면 다음과 같은 문제점을 발견할 수 있다. ResourceSetting의Providers 속성의 유형은 NameTypeElement Collection ResourceProvider Configuration Element이고 설정 요소 유형인 ResourceProvider Configuration Element은 추상적인 유형이다.구체적인 ResourceProvider 설정을 DbResourceProvider Configuration Element과 XmlResource Provider Configuration Element으로 반서열화해야 하는데 전체 설정 시스템에서 이 두 가지 유형의 그림자를 찾을 수 없을 것 같습니다.설정 요소가 실제 형식으로 반서열화되어야 한다는 것을 미리 정하지 못하면 전체 설정의 읽기가 실패합니다.구체적으로 말하면 DbProvider 요소의connectionStringName 속성과 XmlProvider의 fileName 속성을 식별할 수 없습니다. 기본 ResourceProviderConfigurationElement는 관련 속성의 정의가 없기 때문입니다.
기본적으로 구체적인 ResourceProvider의 설정 요소는 반서열화될 수 없고 식별할 수 없는 요소(Unrecognized Element)에 속하기 때문에 우리는 수동으로 반서열화를 실시하기만 하면 구체적인 방법은 Configuration Element Collection의 OnDeserialize Unrecognized Element 방법을 다시 쓰는 것이다.그러나 수동으로 반서열화를 하더라도 구체적인 설정 요소 유형을 정해야 하는데 어떻게 해결할 것인가?만약 당신이 충분히 자세하다면, DbResourceProvider와 XmlResourceProvider를 정의할 때, 클래스에 특수한 사용자 정의 기능을 적용합니다:ConfigurationElementTypeAttribute. 이것은 구체적인 ResourceProvider와 대응하는 설정 요소 간의 일치 관계를 구축합니다.
1
: [ConfigurationElementType(
typeof
(DbResourceProviderConfigurationElement))]
2
:
public
class
DbResourceProvider : IResourceProvider
3
: {
4
:
//
...
5
: }
이 Configuration ElementType Attribute 정의는 매우 간단합니다. 구성 요소의 유형을 나타내는 Configuration ElementType 속성만 정의하고 이 속성은 구조 함수에서 초기화됩니다.
1
: [AttributeUsage( AttributeTargets.Class)]
2
:
public
class
ConfigurationElementTypeAttribute: Attribute
3
: {
4
:
public
Type ConfigurationElementType {
get
;
private
set
; }
5
:
public
ConfigurationElementTypeAttribute(Type configurationElementType)
6
: {
7
:
this
.ConfigurationElementType
=
configurationElementType;
8
: }
9
: }
모든 구체적인 ResourceProvider는 이러한 Configuration ElementType Attribute를 가지고 대응하는 Configuration Element 유형을 지정하기 때문에 우리는 반서열화를 위해 설정 요소의 목표 유형을 정할 수 있습니다.이러한 작업은 RetrieveConfigurationElementType 메서드에서 수행됩니다.
4. ResourceProviderFactory의 정의
NameType Element CollectionT는 OnDeserialize Unrecognized Element 방법을 다시 쓰고 Configuration Element Type Attribute 특성을 빌려 식별할 수 없는 요소에 대한 해석 문제를 해결했다.구체적인 Resource Provider Configuration Element은 모두Create Provider 방법으로 대응하는 Resource Provider를 만들었다. 그러면 Resource Provider Factory의 실현은 매우 간단하다.
1
:
public
static
class
ResourceProviderFactory
2
: {
3
:
public
static
IResourceProvider GetResourceProvider()
4
: {
5
: ResourceSettings settings
=
ResourceSettings.GetConfiguration();
6
:
return
GetResourceProvider(settings.DefaultProvider);
7
: }
8
:
public
static
IResourceProvider GetResourceProvider(
string
name)
9
: {
10
: ResourceSettings settings
=
ResourceSettings.GetConfiguration();
11
:
return
settings.Providers.GetConfigurationElement(name).CreateProvider();
12
: }
13
: }
다섯
제 블로그를 자주 팔로우하시는 분들은 제가 마이크로소프트 오픈 프레임워크 EnterLib에 대해 어느 정도 알고 계신 걸 아실 거예요.EnterLib에 익숙한 친구들은 자주 번거로운 설정에 대해 비난을 하는데, 이것은 확실히 문제이다.그러나 이것은 또 다른 측면에서 EnterLib 베이스 설정 시스템의 강대함을 설명한다. 그렇지 않으면 이렇게 복잡한 설정을 지원하기 어렵다.EnterLib 구성 체계를 통해 사용자 정의 구성을 학습하는 것이 좋습니다.실제로 이 기사에서 식별할 수 없는 설정 요소에 대한 해결 방안은 EnterLib에서 나온 것이다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Visual Studio 2017에서 SQLite를 사용한 Windows Forms 앱 개발Visual Studio 2017에서 SQLite를 사용하여 Windows Forms 앱을 개발해 보았습니다. 아직 서버 탐색기나 TableAdaptor를 사용한 GUI에서의 개발에는 대응하지 않는 것 같습니다. 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.