源码如下:
string className = path + ".User";
return (IUser)Assembly.Load(path).CreateInstance(className);IUser 是个接口
通常我们都是创建对象,上面代码好像是创建一个接口??不解,,
能这样创建接口吗,这样创建接口有什么好处?在BLL中又发现个问题,下面是源码:
private IAdmin dal = DataAccess.CreateAdmin();        #region  IAdmin        /// <summary>
        /// 密码未md5加密
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected int Add(AdminInfo model)
        {
            if (model == null)
            {
                return 0;
            }
            return dal.Add(model);
        }IAdmin 同样也是个接口,可是下面这样用这个接口的 return dal.Add(model);接口又不是对象怎么有方法用了??

解决方案 »

  1.   

      private static readonly string _path = System.Configuration.ConfigurationManager.AppSettings["DAL"];
            /// 通过反射机制,实例化接口对象
            private static object GetInstance(string CacheKey)
            {
                object objType = DataCache.GetCache(CacheKey);
                if (objType == null)
                {
                    try
                    {
                        objType = Assembly.Load(DALFactory._path).CreateInstance(CacheKey);
                        DataCache.SetCache(CacheKey, objType);
                    }
                    catch (Exception ex)
                    {
                        throw ex;
                    }
                }
                return objType;
            }
            public static IUserDAL UserDALInstance()
            {
                string CacheKey = DALFactory._path + ".UserDAL";
                object objType = DALFactory.GetInstance(CacheKey);
                return (IUserDAL)objType;
            }
    创建DALFactory,返回程序集的指定类的实例。 
    创建BLL,调用DALFactory,得到程序集指定类的实例,完成数据操作方法。 
    创建WEB,调用BLL里的数据操作方法。 
      

  2.   

    lz面向对象你还没有学完吧返回的类型可以是接口,这样就可以实现多态,只要是实现了借口的类都可以返回,例如public interface IUser
    {
        void Add(User Model);
    }public class UserDAL:IUser
    {
       public void Add(User Model)
       {
           //。
       }
    }public class UserBLL
    {
       private IUser dal=new UserDAL();//这里可以是反射创建的对象
       
       public void Add(User Model)
       {
           dal.Add(Model);
       }
    }
      

  3.   

    什么乱七八糟的?!这里,Assembly.Load(path).CreateInstance(className)这就创建了一个Object,而不是创建什么IUser。可以这样写:object x=Assembly.Load(path).CreateInstance(className);
    return (IUser)x;
    这样能看懂么?看不懂我可就真没什么办法了。顶多讲一点对象的概念:对象是分类的,因此对象x(或者更准确地说是变量x所引用的那个变量)既有className所代表的类名的那种对象分类,有有许多别的接口,其中就包括IUser。举个例子吧:鸭嘴兽x,它也是爬虫动物x,同时它也是哺乳动物x,同时它还是你的吉祥物x......它有4种分类,甚至更多分类。(不论是class还是interface在面向对象设计上都是类概念)而代码中return时只是明确指示系统去判断这个对象x是否具有IUser那一类或者类型转换函数而已。
    后边那个完全一样的意思,CreateAdmin返回了一个Object,然后赋值给声明为IAdmin类型的变量dal上面而已。不论赋值给什么,对象都还是自己,只是声明变量的类型变了。就好象鸭嘴兽,不论你用哪一个分类来称谓它,它还是它自己。就好象 人rdfpl、男人rdfpl、csdn用户rdfpl,这三个称谓指的是同一个人,我们可以声明三个变量  人 x;
      男人 y;
      csdn用户 z;然后把 人rdfpl 这个对象分别赋值给 x、y、z。不能因为z、y、z的分类不同,你就不承认它们不能代表同一个对象。
      

  4.   

    因此对象x(或者更准确地说是变量x所引用的那个变量)  -->  因此对象x(或者更准确地说是变量x所引用的那个对象)
      

  5.   

    return (IUser)Assembly.Load(path).CreateInstance(className); 这个是接口的概念,就是返回的类的实例可以是接口,只有这样才能实现多态啊
      

  6.   

    不要因为不同变量的声明类型变了,就以为变量所引用的个体也变了。不论声明什么类(包括interface),对象还是它自己,只是我们告诉编译器我们现在要求验证它必须是某种类型(包括interface)。
      

  7.   

    特别是这句很费解//
    dal.Add(model); dal是接口类型的,到这里怎么会像用对象那样用起方法了呢
      

  8.   

    dal是接口类型的 表明它实现了IAdmin 这个接口,可以是IAdmin类型的。但是它该是什么类型还是什么类型
      

  9.   

    一.什么是多态(Polymorphism)
    多态(Polymorphism)是面向对象(Object-Oriented,OO)思想"三大特征"之一,其余两个分别是封装(Encapsulation)和继承(Inheritance)--可见多态的重要性。或者说,不懂得什么是多态就不能说懂得面向对象。多态是一种机制、一种能力,而非某个关键字。它在类的继承中得以实现,在类的方法调用中得以体现。先让我们看看MSDN里给出的定义:Through inheritance, a class can be used as more than one type; it can be used as its own type, any base types, or any interface type if it implements interfaces. This is called polymorphism. In C#, every type is polymorphic. Types can be used as their own type or as a Object instance, because any type automatically treats Object as a base type.译文:通过继承,一个类可以被当作不止一个数据类型(type)使用,它可以被用做自身代表的数据类型(这是最常用的),还可以被当作它的任意基类所代表的数据类型,乃至任意接口类型--前提是这个类实现了这个接口。这一机制称为"多态"。在C#中,所有的数据类型都是多态的。任意一个数据类型都可以被当作自身来使用,也可以当作Object类型来使用(我怀疑原文有问题,那个instance可能是原作者的笔误),因为任何数据类型都自动以Object为自己的基类。呵呵,除非你已经早就知道了什么是多态然后翻过头来看上面一段话,不然我敢打保票--我是清清楚楚的,你是稀里糊涂的。OK,不难为大家了,我用几个句子说明一下多态的思想。我们先把前文中提到的"接口"理解为"一组功能的集合",把"类"理解为功能的实现体。这样的例子多了去了。我们就拿生物界做比喻了:功能集合1:呼吸系统功能集合2:血液循环系统功能集合3:神经系统功能集合4:语言系统类1:灵长类动物。此类实现了1到3功能集合。类2:猴子类。继承自类1。新添加了"爬树"的功能。类3:人类。继承自类1。同时实现了功能集合4。类4:男人类。继承自类3。新添加了"写程序"的功能。类5:女人类。继承自类3。新添加了"发脾气"的功能。作业:请大家把上面的关系用图画出来OK,让我们看下面的话,判断对错:1. 男人是男人 (√) 原因:本来就是!2. 男人是人 (√) 原因:人类是男人类的基类3. 男人是灵长类动物 (√)原因:灵长类是男人类的更抽象层基类4. 男人是会说话的 (√) 原因:男人类的基类实现了语言系统5. 女人是猴子 (×) 原因:如果我这么说,会被蹁死6. 猴子是女人 (×) 原因:女人不是猴子的基类7. 人会写程序 (×)原因:写程序方法是在男人类中才具体实现的8. 女人会发脾气 (√) 原因:因为我说5..哈哈!现在你明白什么是多态了吧!其实是非常简单的逻辑思维。上面仅仅是多态的一个概念,下面我们通过代码去研习一下程序中的多态到底是什么。二.多态的基础--虚函数(virtual)和重写(override)
    很多公司在面试的时候常拿下面几个问题当开胃小菜:1. 如何使用virtual和override?2. 如何使用abstract和override?3. "重写"与"重载"一样吗?4. "重写"、"覆盖"、"隐藏"是同一个概念吗?顺便说一句:如果你确定能把上面的概念很熟练的掌握,发个Mail给我([email protected] ),也许你能收到一份薪水和福利都不错的Offer :p今天我们学习多态,其实就是解决问题1。前面已经提到过,多态机制是依靠继承机制实现的。那么,在常规继承机制的基础之上,在基类中使用virtual函数,并在其派生类中对virtual函数进行override,那么多态机制就自然而然地产生了。小议virtual:呵呵,我这人比较笨--有我的老师和同学为证--学东西奇慢无比,所以当初在C++中学习virtual的历程是我心中永远挥之不去的阴影..倒霉就倒霉在这个"虚"字上了。"实"的我还云里雾里呢,更何况这"虚"的,"虚"的还没搞清楚呢,"纯虚"又蹦出来了,我#@$%!^#&&!..还好,我挺过来了..回顾这段学习历程,我发现万恶之源就是这个"虚"字。在汉语中,"虚"就是"无","无"就是"没有",没有的事情就"不可说"、"不可讲"--那还讲个X??老师也头疼,学生更头疼。拜初中语文老师所赐,我的语言逻辑还算过关,总感觉virtual function译为"虚函数"有点词不达意。找来词典一查,virtual有这样一个词条:Existing or resulting in essence or effect though not in actual fact, form, or name:实质上的,实际上的:虽然没有实际的事实、形式或名义,但在实际上或效果上存在或产生的:例句:the virtual extinction of the buffalo.野牛实际上已经绝迹(隐含的意思是"尽管野牛还木有死光光,但从效果上来讲..")啊哦~~让我想起一句话:有的人活着他已经死了; 有的人死了他还活着..不禁有点惊叹于母语的博大精深--virtual function中的virtual应该译做"名存实亡"而不是"虚"!OK,下面就让我们看看类中的virtual函数是怎么个"名存实亡"法。例子1: 非virtual / override程序using System;
    using System.Collections.Generic;
    using System.Text;namespace Sample
    {
    // 演员(类)
    class Actor
    {
    public void DoShow()
    {
    Console.WriteLine("Doing a show...");
    }
    }// 乐手(类),继承自Actor类
    class Bandsman : Actor
    {
    // 子类同名方法隐藏父类方法
    // 其实标准写法应该是:
    // public new void DoShow(){...}
    // 为了突出"同名",我把new省了,编译器会自动识别
    public void DoShow()
    {
    Console.WriteLine("Playing musical instrument...");
    }
    }// 吉他手(类),继承自Bandsman类
    class Guitarist : Bandsman
    {
    public new void DoShow()
    {
    Console.WriteLine("Playing a guitar solo...");
    }
    }class Program
    {
    static void Main(string[] args)
    {
    // 正常声明
    Actor actor = new Actor();
    Bandsman bandsman = new Bandsman();
    Guitarist guitarist = new Guitarist();// 一般情况下,随着类的承继和方法的重写
    // 方法是越来越具体、越来越个性化
    actor.DoShow();
    bandsman.DoShow();
    guitarist.DoShow();Console.WriteLine("===========================");//尝试多态用法
    Actor myActor1 = new Bandsman(); //正确:乐手是演员
    Actor myActor2 = new Guitarist(); //正确:吉他手是演员
    Bandsman myBandsman = new Guitarist(); //正确:吉他手是乐手//仍然调用的是引用类型自身的方法,而非派生类的方法
    myActor1.DoShow();
    myActor2.DoShow();
    myBandsman.DoShow();
    }
    }
    }代码分析:1. 一上来,演员类、乐手类、吉他手类形成一个继承链。2. 乐手类和吉他手类作为子类,都把其父类的DoShow()方法"隐藏"了。3. 特别强调:"隐藏"不是"覆盖",后面要讲的"重写"才是真正的"覆盖"。4. 隐藏是使用new修饰符实现的,但这个修饰符可以省略。5. 隐藏(Hide)的含意是:父类的这个函数实际上还在,只是被子类的同名"藏起来"了。6. 重写(override)与覆盖是同一个含意,只是覆盖并非编程的术语,但"覆盖"比较形象。7. 主程序代码的上半部分是常规使用方法,没什么好说的。8. 主程序代码的下半部分已经算是多态了,但由于没有使用virtual和override,多态最有价值的效果--个性化方法实现--没有体现出来。后面的例子专门体现这一点。例子2: 应用virtual / override,真正的多态
    using System;
    using System.Collections.Generic;
    using System.Text;namespace Sample
    {
    // 演员(类)
    class Actor
    {
    // 使用了virtual来修饰函数
    // 此函数已经"名存实亡"了
    public virtual void DoShow()
    {
    Console.WriteLine("Doing a show...");
    }
    }// 乐手(类),继承自Actor类
    class Bandsman : Actor
    {
    // 使用了override来修饰函数
    // 此函数将取代(重写)父类中的同名函数
    public override void DoShow()
    {
    Console.WriteLine("Playing musical instrument...");
    }
    }// 吉他手(类),继承自Bandsman类
    class Guitarist : Bandsman
    {
    public override void DoShow()
    {
    Console.WriteLine("Playing a guitar solo...");
    }
    }class Program
    {
    static void Main(string[] args)
    {
    // 正常声明
    Actor actor = new Actor();
    Bandsman bandsman = new Bandsman();
    Guitarist guitarist = new Guitarist();// 一般情况下,随着类的承继和方法的重写
    // 方法是越来越具体、越来越个性化
    actor.DoShow();
    bandsman.DoShow();
    guitarist.DoShow();Console.WriteLine("===========================");//尝试多态用法
    Actor myActor1 = new Bandsman(); //正确:乐手是演员
    Actor myActor2 = new Guitarist(); //正确:吉他手是演员
    Bandsman myBandsman = new Guitarist(); //正确:吉他手是乐手// Look!!!// 调用的是引用类型所引用的实例的方法// 引用类型本身的函数是virtual的// 看似"存在",实际已经被其子类重写(不是隐藏,而是被kill掉了)// 这正是virtual所要表达的"名存实亡"的本意,而非一个"虚"字所能传达
    myActor1.DoShow();
    myActor2.DoShow();
    myBandsman.DoShow();
    }
    }
    }代码分析:1. 除了将继承链中最顶层基类的DoShow()方法改为用virtual修饰;把继承链中派生类的DoShow()方法改为override修饰以重写基类的方法。2. 主程序代码没变,但下半部分产生的效果完全不同!请体会"引用变量本身方法"与"引用变量所引用实例的方法"的不同--这是关键。多态成因的分析:为什么会产生这样的效果呢?这里要提到一个"virtual表"的问题。我们看看程序中继承链的构成:Actor à Bandsman à Guitarist。因为派生类不但继承了基类的代码(确切地说是public代码)而且还有自己的特有代码(无论是不是与基类同名,都是自己特有的)。从程序的逻辑视角来看,你可以这样想象:在内存中,子类的实例所占的内存块是在父类所占的内存块的基础上"追加"了一小块--拜托大家自己画画图。这多出来的一小块里,装的就是子类特有的数据和代码。我们仔细分析这几句代码:1. Actor actor = new Actor(); //常规的声明及分配内存方法
    因为类是引用类型,所以actor这个引用变量是放在栈里的、类型是Actor类型,而它所引用的实例--同样也是Actor类型的--内存由new操作符来分配并且放在堆里。这样,引用变量与实例的类型一模一样、完全匹配。换句话说:栈里的引用变量所能"管理"的堆中的内存块大小正好、不多也不少。2. Actor myActor1 = new Bandsman(); //正确:乐手是演员
    同样是这句代码,在两个例子中产生的效果完全不同。为什么呢?且看!在例1中,在Bandsman类中只是使用new将父类的DoShow()给隐藏了--所起的作用仅限于自己对父类追加的代码块中,丝毫没有影响到父类。而栈中的引用变量是Actor类型的myActor1,它只能管理Actor类实例所占的那么大一块内存,而对追加的内存毫无控制能力(或者说看不见追加的这块内存)。因此,当你使用myActor1.DoShow();调用成员方法时,myActor1只能使唤自己能管到的那块内存里的DoShow()方法。那么例2中呢?难道例2中的myActor1就能管理追加的一块内存了吗?否也!它仍然管理不了,但不要忘了--这时候Actor类中的DoShow()方法已经被virtual所修饰,同时Bandsman类中的DoShow()方法已经被override修饰。这时候,当执行myActor1.DoShow();一句时,myActor1调用自己所管辖的内存块时,发现DoShow()这个函数已经标记为"可被重写"了(其实,在VB.NET中,与C#的virtual关键字对应的关键字就是Overridable,更直白),那么它就会尝试去发现有没有override链(也就是virtual表,即"虚表")的存在,如果存在,那么就调用override链上的最新可用版本--这就有了我们在例2中看到的效果。3. Actor myActor2 = new Guitarist(); //正确:吉他手是演员
    通过这句代码,你也可以想象一下2级重写是怎么形成的,同时也可以感悟一下所谓"重写链上最新的可用版本"是什么意思。4. Guitarist myActor2 = new Actor(); //错误:想一想为什么?
    呵呵,这是错误的,原因是引用变量所管理的内存大小超出了实例实际的内存大小。乱弹:多态,台湾的兄弟们喜欢称"多型",一样的。"多"表示在实例化引用变量的时候,根据用户当时的使用情况(这时候程序已经Release了,不能再修改了,程序员已经不能控制程序了)智能地给出个性化的响应。多,谓之变。莫非"多态"亦可称为"变态"耶?咦.."变型"..让我想起Transformer来了。
      

  10.   

    楼主好像少写了一些内容,楼主的程序中应该还要说明一下User或Admin类没有继承IAdmin接口
     public class Admin
        {
            private IAdmin dal = DataAccess.CreateAdmin();        #region  IAdmin        /// <summary>
            /// 密码未md5加密
            /// </summary>
            /// <param name="model"></param>
            /// <returns></returns>
            protected int Add(AdminInfo model)
            {
                if (model == null)
                {
                    return 0;
                }
                return dal.Add(model);
            }