天天看點

解除安裝Class?

由于在Java中有一個可以自己替換的ClassLoader,是以在Eclipse中很容易管理成千上萬的插件,可以在同一個應用域中自由地裝載和解除安裝。在運作時為某個Class重新定義一個ClassLoader并且重新執行個體化,原來加載的東西就交給GC了。這個機制還有一個我一直夢想的一個價值就是在Load一個Class到應用域的時候運作某些方法,例如讀出配置檔案。如果配置檔案中涉及到一些額外的Class需要更替就不必重新啟動應用程式了。這對于需要類似熱部署的場合非常有用。

在.net中沒有這麼幸運。Assembly是決不能被解除安裝的。有一個解決方案是通過解除安裝AppDomain的方式來解除安裝一系列的Assembly。經過一小番試驗,跨域的調用是可以實作的,不過需要遵循一點點小規則。

一、隻有自MashalByRefObject派生的類型可以跨應用域通路。因為Calling的域使用的中Executing域中的執行個體通過Unwrap出來的代理類,是以其實并不是真正的“跨應用域”,而是類似Remoting的方式。

二、所有傳遞的資料類型必須是加上Serializable Attribute的類型。

我的應用場景是通過選項在運作時替換一個已更新的Assembly依賴。這個依賴顯然不能寫到主應用程式所依賴的Assembly清單中,而是通過從配置文檔讀出其相關的Assembly并從指定位置加載。

下面的例子是讀出一個Assembly中的所有類型并将其繼承關系顯示到一個TreeView中。

這是個用來傳遞類型資訊的資料類型:

解除安裝Class?
解除安裝Class?

    /**//// <summary>

解除安裝Class?

    /// 可在應用域間傳遞的詳細類型資訊

解除安裝Class?

    /// </summary>

解除安裝Class?

    [Serializable]

解除安裝Class?

    public class TypeInfo

解除安裝Class?
解除安裝Class?
解除安裝Class?

{

解除安裝Class?

        public TypeInfo(Type type)

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

            _Name = type.Name;

解除安裝Class?

            _FullName = type.FullName;

解除安裝Class?

            _BaseName = type.BaseType.FullName;

解除安裝Class?

        }

解除安裝Class?
解除安裝Class?

        private string _Name, _FullName, _BaseName;

解除安裝Class?
解除安裝Class?

        public string Name

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

            get

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

                return _Name;

解除安裝Class?

            }

解除安裝Class?
解除安裝Class?
解除安裝Class?

        public string FullName

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

                return _FullName;

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

        public string BaseName

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

                return _BaseName;

解除安裝Class?
解除安裝Class?
解除安裝Class?

    }

解除安裝Class?

這是個裝載器:

解除安裝Class?
解除安裝Class?
解除安裝Class?

    /// 跨域工作的程式集裝載器

解除安裝Class?
解除安裝Class?

    public class AssemblyLoader : MarshalByRefObject

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

        public TypeInfo [] GetAssemblyTypeInfos(string path)

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

            Assembly assembly = Assembly.LoadFile(path);

解除安裝Class?

            Type [] types = assembly.GetExportedTypes();

解除安裝Class?

            TypeInfo [] typeInfos = new TypeInfo[types.Length];

解除安裝Class?

            int i = 0;

解除安裝Class?

            foreach (Type t in types)

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

                typeInfos[i ++] = new TypeInfo(t);

解除安裝Class?
解除安裝Class?

            return typeInfos;

解除安裝Class?
解除安裝Class?
解除安裝Class?

剩下的就是用戶端代碼了,拿到這個清單生成TreeView就沒什麼困難了:

解除安裝Class?

            private TypeInfo [] GetTypeInfos(string path)

解除安裝Class?
解除安裝Class?
解除安裝Class?
解除安裝Class?

                AppDomain appDomain = AppDomain.CreateDomain("TemporaryAssembly");

解除安裝Class?

                Type t = typeof(AssemblyLoader);

解除安裝Class?

                AssemblyLoader loader = (AssemblyLoader) appDomain.CreateInstance(t.Assembly.FullName, t.FullName).Unwrap();

解除安裝Class?

                TypeInfo [] typeInfos = loader.GetAssemblyTypeInfos(path);

解除安裝Class?

                AppDomain.Unload(appDomain);

解除安裝Class?

                return typeInfos;

解除安裝Class?
解除安裝Class?

繼續閱讀