.NET에서 제공하는 반사 메커니즘을 사용하면 플러그인을 쉽게 로드할 수 있습니다. 이 문서에서는 필요한 플러그인을 유연하고 올바르게 로드할 수 있는 방법을 제공합니다.
.NET에서 전체 유형 이름의 형식은 "유형 이름, 어셈블리 이름"입니다.
예: "System.Configuration.NameValueSectionHandler, 시스템, 버전=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089".
형식 이름은 System.Configuration.NameValueSectionHandler이며 네임스페이스가 포함된 전체 형식 이름입니다.
유형을 사용하여 FullName을 가져올 수도 있습니다.
예: 문자열 typeName = typeof(NameValueSectionHandler).FullName;
어셈블리 이름은 "System, Version=1.0.3300.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"입니다.
어셈블리 이름은 System이며 시스템은 해당 확장명(예: System.dll 또는 System.exe)을 자동으로 조정합니다.
Version, Culture 및 PublicKeyToken은 어셈블리의 특정 버전, 문화적 배경 및 서명입니다. 특별한 요구 사항은 없으며 생략할 수 있습니다.
유형 이름을 기반으로 필요한 유형을 동적으로 로드할 수 있습니다. 좋다:
string typeName = "System.Configuration.NameValueSectionHandler, 시스템";
유형 t = Type.GetType(typeName);
객체 obj = Activator.CreateInstance(t);
//또는
System.Configuration.NameValueSectionHandler obj = (System.Configuration.NameValueSectionHandler)Activator.CreateInstance(t);
이 시점에서 obj는 필수 유형 인스턴스입니다.
일반적으로 플러그인은 특정 인터페이스를 구현해야 하는 클래스입니다. 따라서 플러그인을 로드하기 전에 플러그인 유형이 적합한지 확인해야 합니다.
예를 들어 플러그인의 인터페이스가 IPlugin인 경우 다음과 같은 방법으로 식별할 수 있습니다.
문자열 인터페이스 이름 = typeof(IPlugin).FullName;
string typeName = "Muf.MyPlugin, MyPlugin";
유형 t = Type.GetType(typeName);
if (t == null
|| !t.IsClass
|| !t.IsPublic
|| t.GetInterface(인터페이스이름) == null)
{
return null; // 필수 플러그인이 아닙니다.
}
위의 코드를 요약하면 플러그인 로드를 위한 일반적인 코드를 만들 수 있습니다.
/**//// <요약>
/// 지정된 인터페이스가 있는 유형을 동적으로 로드하고 생성합니다.
/// </summary>
/// <param name="className">유형 이름</param>
/// <param name="interfaceName">지정된 인터페이스 이름</param>
/// <param name="param">생성자의 매개변수를 지정합니다(null 또는 빈 배열은 기본 생성자를 호출하는 것을 의미합니다)</param>
/// <returns>생성된 유형을 반환합니다(null은 유형을 생성할 수 없거나 찾을 수 없음을 의미함)</returns>
공용 정적 개체 LoadObject(문자열 클래스 이름, 문자열 인터페이스 이름, 개체[] 매개변수)
{
노력하다
{
유형 t = Type.GetType(클래스이름);
if (t == null
|| !t.IsClass
|| !t.IsPublic
|| t.IsAbstract
|| t.GetInterface(인터페이스이름) == null)
{
null을 반환;
}
객체 o = Activator.CreateInstance(t, param);
if( o == null )
{
null을 반환;
}
반환 오;
}
catch(예외예외)
{
null을 반환;
}
}
나중에 LoadObject를 사용하여 필요한 플러그인을 로드할 수 있습니다.
플러그인은 일반적으로 구성 파일에 배치되고 프로그램에서 읽습니다.
구성 파일 예(구성 파일 사용에 대한 관련 에세이 참조):
<?xml version="1.0" 인코딩="utf-8" ?>
<구성>
<config섹션>
<section name="Channels" type="Vmp.Configuration.ChannelsSectionHandler, 통신" />
</configSections>
<채널>
<채널
ChannelType="Vmp.Communication.TcpChannel, 통신"
TraceFile="d:logchannel1.log"
포트="2020" MaxConnections="300" 버퍼 크기="2048"
/>
</채널>
</구성>
코드 예:
private ArrayListchannelList = new ArrayList();
private LoadChannels()
{
ArrayList 채널 구성 = (ArrayList)ConfigurationSettings.GetConfig( "채널" );
foreach(channelConfig의 해시 테이블 구성)
{
string 채널 유형 = (문자열) config["ChannelType"];
IChannel 채널 = (IChannel) CommonUtils.LoadObject(channelType, typeof(IChannel).FullName, new object[]{config});
if(채널 == null)
계속;
채널 목록.추가(채널);
}
또한 지정된 플러그인 디렉터리를 탐색하여 요구 사항을 충족하는 모든 플러그인을 로드할 수도 있습니다. 예:
public IPlugin[] LoadAllPlugIn(stringpluginDir)
{
//기본 플러그인 디렉토리 설정
if(pluginDir == null || 플러그인Dir == "")
플러그인Dir = "./PlugIns";
// 플러그인 인터페이스 이름을 가져옵니다.
string interfaceName = typeof(IPlugin).FullName;
// 플러그인을 저장하는 데 사용되는 배열
ArrayList arr = new ArrayList();
// 플러그인 디렉터리를 탐색합니다(플러그인이 dll 파일이라고 가정).
foreach(Directory.GetFiles(pluginDir, "*.dll")의 문자열 파일)
{
//플러그인 파일 로드
어셈블리 asm = Assembly.LoadFile(파일);
// 내보낸 플러그인 클래스를 탐색합니다.
foreach(asm.GetExportedTypes()에 t를 입력하세요.)
{
//플러그인을 로드합니다. 플러그인이 지정된 인터페이스를 따르지 않으면 null을 반환합니다.
IPlugin 플러그인 = LoadObject(t.FullName, 인터페이스 이름, null) as IPlugin
if(plugin != null)
arr.Add(플러그인);
}
}
// 플러그인으로 돌아가기
return (IPlugin[])arr.ToArray(typeof(IPlugin));
}