作者toki (いまがその时だ)
看板C_Sharp
标题Re: [问题] plugin实作方法?
时间Fri Sep 25 00:25:55 2009
※ 引述《Syung1983 (小永)》之铭言:
: 请问一下 应用程式可新增功能,类似plugin的方法如何实作?
: 举例来说有功能 A、B、C、D、E等模组,模组间互相独立或相依
: 使用者如果需要A的功能,则安装A模组就好。
: 如果需要C跟D的功能,则安装这两个模组就可以给另一位使用者
: 请问网路上有在讨论此种作法的网站吗?
: 目前我从网路上找到的资料只有
: Michael Tsai大所提到的: 动态型别应用例:动态载入 DLL模组
: 请问一下如果要搜寻的关键字应该使用什麽
要做 plug-in,首先你要搞清楚有什麽 function 和 proerty
甚至是 delegate 是需要共用的
然後你必需把它们订成 interface,并且实作它编成 class library dll
举个我以前有个做到一半的网路相簿下载器当例子:
(
真的有兴趣的,完整的 source code 在 SourceForge 上
http://t-photo-ripper.svn.sourceforge.net/viewvc/t-photo-ripper/
Code 应该是可以 build,不过上面的 plug-in 应该都因为太久没更新而没用了
)
首先我订出了一个 IPhotoRipperPlugIn 的 interface
这是所有的下载 plug-in 都必需要实作的 function 以及 property
public interface IPhotoRipperPlugIn
{
string PlugInName { get; }
string Author { get; }
string TargetSiteURL { get; }
URLType GetURLType(string aURL);
AlbumList GetAlbumList(string aURL, string aReferer);
AlbumList GetAlbumList(string aURL, string aReferer,
string aUsername, string aPassword);
AlbumPicList GetAlbumPicList(string aURL, string aReferer);
AlbumPicList GetAlbumPicList(string aURL, string aReferer,
string aUsername, string aPassword);
string GetLoginedCookie(string aUsername, string aPassword);
}
举一个简单的例子来说,每一个 PlugInName 都必需要实作 TargetSiteURL property
这样才能透过问每个 plugin 的 TargetSiteURL,来得知 plugin 是针对哪个网站的
接下来是实作:
// PlugIn.cs (1)
namespace TPhotoRipperPlugIn
{
public class
PlugIn : IPhotoRipperPlugIn
{
public string PlugInName
{
get { return "KTXP"; }
}
public string TargetSiteURL
{
get { return "
http://comic.ktxp.com/"; }
}
}
}
// PlugIn.cs (2)
namespace TPhotoRipperPlugIn
{
public class
PlugIn : IPhotoRipperPlugIn
{
public string PlugInName
{
get { return "DMZJ"; }
}
public string TargetSiteURL
{
get { return "
http://comic.dmzj.com/"; }
}
}
}
像上面的情形你问 PlugIn (1) 它的 TargetSiteURL 就会是
http://comic.ktxp.com/
PlugIn (2) 就会回答你
http://comic.dmzj.com/
这当然只是节录,真的 class 要把整个 interface 的东西都实作完
这两个 class 分属两个 plug-in,为了方便载入起见,两个 plug-in 的实作 class
都叫做 PlugIn,并且都位於 TPhotoRipperPlug namesapce 下
接下来是实际载入的部分
public class TPhotoRipperPlugInLoader
{
private Assembly _asmb;
private Object _obj;
private IPhotoRipperPlugIn _plugIn;
private string _lastError;
public TPhotoRipperPlugInLoader(string aPlugInPath)
{
if (!File.Exists(aPlugInPath))
{
_lastError = "DLL file not exists.";
return;
}
try
{
// 由 Assembly.LoadFrom 载入 dll 档案
// 并产生 Assembly
_asmb = Assembly.LoadFrom(aPlugInPath);
if (_asmb == null)
{
_lastError = "Load PlugIn assembly failed";
return;
}
//由 CreateInstance 建立一个宣告在
//TPhotoRipperPlugIn namespace 下
//名字叫做 PlugIn 的 class 的实体物件
_obj = _asmb.CreateInstance(
"
TPhotoRipperPlugIn.PlugIn"
);
//由该物件 query 出 plugin 共通的 interface
_plugIn = (IPhotoRipperPlugIn)_obj;
}
catch (Exception e)
{
_lastError = e.Message;
}
}
public bool isReady { get { return _plugIn != null; } }
public bool hasError { get { return _lastError != ""; } }
public string lastError { get { return _lastError; } }
// 由此 property 就可以使用 query 出来的 IPhotoRipper interface
public IPhotoRipperPlugIn plugIn { get { return _plugIn; } }
}
不过这只是单一用途 plug-in,其它多种类 plug-in 串连基本上差不多
但是要考虑的东西就更多了,多种的宣告可能会像这样
interface IURLFetcher
{
string Fetch(string URL);
}
interface IURLParser
{
string PlugInName {get;}
void SetURLFetcherPlugIn(interface IURLFetcher);
}
由多个 interface 组合起来
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 112.104.91.27
※ 编辑: toki 来自: 112.104.91.27 (09/25 00:27)
※ 编辑: toki 来自: 112.104.91.27 (09/25 00:28)
1F:推 Syung1983:感谢大大的范例,先研究看看 09/29 09:17