none
绑定接口属性到控件,异常:不能绑定父接口的属性 RRS feed

  • 问题

  • 发现一个问题,各位兄弟们看看。偶是新手,多多指教啊。


    实体类以及相关接口定义如下:
      public interface ISerialObject {
                    int UID { get; }
                    string Name { get; set; }
      }

      public interface IChem : ISerialObject {
                      string RptName { get; set; }
        }

        public class Chem : IChem {
              public Chem() {
                        id = ++no;
                        Name = id.ToString();
                        RptName = Name + Name;
              }
              private static int no = 0;
              private int id;
              public int UID {
                          get{
                          return id;
                      }
              }

            private string name;
            public string Name {
                        get { return name; }
                        set { name = value; }
                }

              private string rptName;
              public string RptName {
                        get { return rptName; }
                        set { rptName = value; }
              }

              public static IChem Create()
              {
                        return new Chem();
              }
    }

    窗口有2个TextBox用来绑定数据源

    private BindingSource bindSrc = new BindingSource();//定义为窗口成员变量

    private void Form1_Load(object sender, EventArgs e)
    {

          BindingList <IChem> curr = new BindingList <IChem>();
          curr.Add( Chem.Create() );
          curr.Add(Chem.Create());

          bindSrc.DataSource = curr;

          ISerialObject d = (ISerialObject)curr[0];
          IChem f = (IChem)d;//调试时,看内存,居然只有RptName,Name好像不可见
          f.Name = "22";//但是可以直接修改Name

          Binding nameBinding = this.textBox1.DataBindings.Add("Text", bindSrc,  “RptName", true);//正常运行
          nameBinding = this.textBox2.DataBindings.Add("Text", bindSrc, "Name", true);//异常 ,报错。
    }

    如果全换成类,试下缺可以
    我整理下代码格式,请大家看看
    高手分析下原因:)多谢了
    2009年6月26日 14:27

答案

  • Hi 楼主您好,
    我想我们是不是进入了一个误区即:认为接口继承等于实现继承(以System.Object为基类的继承,即我们通常理解的继承)。
    接口继承是指继承了一个约定或是方法的签名。不包含任何的实现,所以不能期望接口的继承与普通的继承一样来使用。
    本例中IChem : ISerialObject只能说明将来对IChem的实现例如Chem必须实现IChem 和ISerialObject所约定的方法。
    摘用JeffreyRichter所著一书《CLR via C#》的一段话:“I use the word inherit here rather loosely because interface inheritance doesn't work exactly as does class inheritance.
    I prefer to think of interface inheritance as including the contracts of the IEnumerable<T> and IEnumerable interfaces.”

    所以我想为了保持您设计的接口,以及多态的优点是不是可以用抽象类来作为绑定的父类。我将代码修改如下:
    public interface ISerialObject
        {
            int UID { get; }
            string Name { get; set; }
        }

        public interface IChem : ISerialObject
        {
            string RptName { get; set; }
        }
        public abstract class AbsChem : IChem
        {
            public abstract int UID { get; }
            public abstract string Name { get; set; }
            public abstract string RptName { get; set; }
        }
        public class Chem : AbsChem
        {
            public Chem()
            {
                id = ++no;
                Name = id.ToString();
                RptName = Name + Name;
            }
            private static int no = 0;
            private int id;
            public override int UID
            {
                get
                {
                    return id;
                }
            }

            private string name;
            public override string Name
            {
                get { return name; }
                set { name = value; }
            }

            private string rptName;
            public override string RptName
            {
                get { return rptName; }
                set { rptName = value; }
            }

            public static AbsChem Create()
            {
                return new Chem();
            }


        }
    private void Form1_Load(object sender, EventArgs e)
    {


    BindingList<AbsChem> curr = new BindingList<AbsChem>();
                curr.Add(Chem.Create());
                curr.Add(Chem.Create());

                bindSrc.DataSource = curr;

                 ISerialObject d = (ISerialObject)curr[0];
           IChem f = (IChem)d;//调试时,看内存,居然只有RptName,Name好像不可见 //<font color="blue">个人认为这里就是体现接口与普通的继承不同概念的地方</font>
           f.Name = "22";//但是可以直接修改Name  // 这是因为f指向chem的引用

     

          Binding nameBinding = this.textBox1.DataBindings.Add("Text", bindSrc,  "RptName", true);//正常运行
          nameBinding = this.textBox2.DataBindings.Add("Text", bindSrc, "Name", true);//异常 ,报错。 //改为抽象类后已不抱错
    }

    2009年6月29日 16:18

全部回复

  • 发现一个问题,各位兄弟们看看。偶是新手,多多指教啊。


    实体类以及相关接口定义如下:
       public interface ISerialObject {
                     int UID { get; }
                     string Name { get; set; }
       }

       public interface IChem : ISerialObject {
                      string RptName { get; set; }
        }

        public class Chem : IChem {
              public Chem() {
                         id = ++no;
                         Name = id.ToString();
                         RptName = Name + Name;
              }
              private static int no = 0;
              private int id;
              public int UID {
                          get{ 
                           return id;
                      }
              }

             private string name;
             public string Name {
                         get { return name; }
                         set { name = value; }
                }

              private string rptName;
              public string RptName {
                         get { return rptName; }
                         set { rptName = value; }
               }

               public static IChem Create()
              {
                         return new Chem();
               }
    }

    窗口有2个TextBox用来绑定数据源

    private BindingSource bindSrc = new BindingSource();//定义为窗口成员变量

    private void Form1_Load(object sender, EventArgs e)
    {

           BindingList<IChem> curr = new BindingList<IChem>();
           curr.Add( Chem.Create() );
           curr.Add(Chem.Create());

           bindSrc.DataSource = curr;

           ISerialObject d = (ISerialObject)curr[0];
           IChem f = (IChem)d;//调试时,看内存,居然只有RptName,Name好像不可见
           f.Name = "22";//但是可以直接修改Name

          Binding nameBinding = this.textBox1.DataBindings.Add("Text", bindSrc,  “RptName", true);//正常运行
          nameBinding = this.textBox2.DataBindings.Add("Text", bindSrc, "Name", true);//异常 ,报错。
    }

    如果全换成类,试下却可以
    请高手分析下原因,并给出解决办法:)多谢了

    2009年6月27日 3:07
  • 你好!
         你使用的是这个接口:
       public interface IChem : ISerialObject {
                      string RptName { get; set; }
        }

         通过这个接口从ISerialObject继承了Name属性
    周雪峰
    2009年6月27日 5:15
    版主
  • IChem  不是 从ISerialObject  继承,应该可以访问其基接口的ISerialObject 的属性Name?
    继承不起效果?
    2009年6月27日 7:12
  • 就是需要继承Name属性,现在问题:就是不能绑定IChem的属性Name到TextBox,报错,是什么ArgumentInvalid。。
    2009年6月27日 7:15
  • 你的class chem 中
    private string name;
             public string Name {
                         get { return name; }
                         set { name = value; }
                }
    更改一下
    改成:public new string Name
    具体信息你可以看下
    http://www.cnblogs.com/anytao/archive/2007/04/28/must_net_05.html

    莫让青春付流水
    2009年6月27日 17:59
  • 你好,

    你把下面这个返回接口对象改成返回Chem对象。
    public static IChem Create()
              {
                         return new Chem();
               }
    然后把下面这个构造IChem集合改成构造Chem集合。
      BindingList<IChem> curr = new BindingList<IChem>();

    个人认为DataBind.Add方法中对source有限制,这个方法只能找到顶级的field。
    你的IChem是从Chem转化来的,所以它除了自己本身定义的RptName顶级元素外,还有一个指向Chem的类似指针一样的引用。


    Microsoft Online Community Support
    2009年6月29日 5:18
  • TO KeFang Chen:
    如果直接用Chem的话,就失去了接口的意义。本来想用接口来实现依赖导致,以达到UI依赖接口,业务层(比如Chem的实现)也只依赖接口。

    。。。。。。郁闷。。。。。。。。。。

    难道C#里面不需要考虑这些?即使UI直接调用Chem,Chem改变也不会影响UI?
    2009年6月29日 9:48
  • 你好,
    我个人意见如下:

    1.在你的项目中在你的这个环境下,你说的依赖IChem和依赖Chem有区别吗。
    Chem只是IChem的一个实现。所以我认为没有区别。

    Microsoft Online Community Support
    2009年6月29日 10:02
  • 你好!
         如果想使用接口的话,需要重新设计接口啊!
    周雪峰
    2009年6月29日 11:41
    版主
  • TO KeFangChen:
         Chem只是IChem的一个实现,但是实际情况是,Chem会依赖数据库,因为我用了activerecord的东东,所以不想UI依赖Chem,而是依赖IChem。
    我对C#.net不熟悉,MS提倡这样使用?原因何在?
       
       

    2009年6月29日 12:26
  • To 周学峰:
        重新设计接口?这样不对?具体指导下嘛,我不太明白
    把IChem与ISerialObject合了?   我目前用了这种方法来规避不能绑定的问题,可其实没必要重新设计接口吧?
    2009年6月29日 12:30
  • Hi 楼主您好,
    我想我们是不是进入了一个误区即:认为接口继承等于实现继承(以System.Object为基类的继承,即我们通常理解的继承)。
    接口继承是指继承了一个约定或是方法的签名。不包含任何的实现,所以不能期望接口的继承与普通的继承一样来使用。
    本例中IChem : ISerialObject只能说明将来对IChem的实现例如Chem必须实现IChem 和ISerialObject所约定的方法。
    摘用JeffreyRichter所著一书《CLR via C#》的一段话:“I use the word inherit here rather loosely because interface inheritance doesn't work exactly as does class inheritance.
    I prefer to think of interface inheritance as including the contracts of the IEnumerable<T> and IEnumerable interfaces.”

    所以我想为了保持您设计的接口,以及多态的优点是不是可以用抽象类来作为绑定的父类。我将代码修改如下:
    public interface ISerialObject
        {
            int UID { get; }
            string Name { get; set; }
        }

        public interface IChem : ISerialObject
        {
            string RptName { get; set; }
        }
        public abstract class AbsChem : IChem
        {
            public abstract int UID { get; }
            public abstract string Name { get; set; }
            public abstract string RptName { get; set; }
        }
        public class Chem : AbsChem
        {
            public Chem()
            {
                id = ++no;
                Name = id.ToString();
                RptName = Name + Name;
            }
            private static int no = 0;
            private int id;
            public override int UID
            {
                get
                {
                    return id;
                }
            }

            private string name;
            public override string Name
            {
                get { return name; }
                set { name = value; }
            }

            private string rptName;
            public override string RptName
            {
                get { return rptName; }
                set { rptName = value; }
            }

            public static AbsChem Create()
            {
                return new Chem();
            }


        }
    private void Form1_Load(object sender, EventArgs e)
    {


    BindingList<AbsChem> curr = new BindingList<AbsChem>();
                curr.Add(Chem.Create());
                curr.Add(Chem.Create());

                bindSrc.DataSource = curr;

                 ISerialObject d = (ISerialObject)curr[0];
           IChem f = (IChem)d;//调试时,看内存,居然只有RptName,Name好像不可见 //<font color="blue">个人认为这里就是体现接口与普通的继承不同概念的地方</font>
           f.Name = "22";//但是可以直接修改Name  // 这是因为f指向chem的引用

     

          Binding nameBinding = this.textBox1.DataBindings.Add("Text", bindSrc,  "RptName", true);//正常运行
          nameBinding = this.textBox2.DataBindings.Add("Text", bindSrc, "Name", true);//异常 ,报错。 //改为抽象类后已不抱错
    }

    2009年6月29日 16:18
  • 如果你使用Visual Studio 2008的话,建议在调试的时港跟踪到BindingList的源代码里面去看看
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful. This posting is provided "AS IS" with no warranties, and confers no rights.
    Visual C++ MVP
    2009年6月29日 16:27
    版主
  • TO Jiyuan:
         谢谢你关于Interface与class的介绍。

    2009年6月30日 0:56
  • TO Jiyuan:
         这意味着必须以抽象类实现接口层。。。。。。
    暂且如此理解吧
    2009年6月30日 0:58
  • To 羊天师:

        接口的设计在我的理解最大的用途是分解行为制定规约,虽然用起来简单,但接口背后所包含的知识是很复杂的。
        在设计重用的领域,比如框架的设计,在使用接口和抽象行为时,都会具体指定需要用到的接口是什么,然后调用其行为,(属性的本质也是方法来实现的)
    所以当您需要这么用时:nameBinding = this.textBox2.DataBindings.Add("Text", bindSrc, "Name", true);//
    则表示bindSrc代表的是ISerialObject 而不是IChem。
    当您要这么用时:nameBinding = this.textBox1.DataBindings.Add("Text", bindSrc,  “RptName", true);//
    则表示bindSrc代表的是IChem 而不是ISerialObject。
    个人理解,敬请参考!
    • 已编辑 Jiyuan 2009年6月30日 4:34
    2009年6月30日 4:03
  • TO All: 谢谢各位的建议。我另开一贴讨论接口的问题。
    谢谢各位。。
    2009年6月30日 5:26