Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/336.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在.NET中初始化基类_C#_.net_Oop - Fatal编程技术网

C# 在.NET中初始化基类

C# 在.NET中初始化基类,c#,.net,oop,C#,.net,Oop,如果需要使用现有对象初始化对象的基础,该如何进行?例如,在此场景中: public class A { public string field1; public string field2; } public class B : A { public string field3; public void Assign(A source) { this.base = source; // <-- will not work, what

如果需要使用现有对象初始化对象的基础,该如何进行?例如,在此场景中:

public class A
{
    public string field1;
    public string field2;
}

public class B : A
{
    public string field3;
    public void Assign(A source)
    {
        this.base = source; // <-- will not work, what can I do here?
    }
}
公共A类
{
公共字符串字段1;
公共字符串字段2;
}
B级:A级
{
公共字符串字段3;
公共无效分配(源)
{

this.base=source;//不,您尝试的语法是不可能的。在C#.NET中,您需要执行以下操作:

public void Assign(A source) {
    field1 = source.field1;
    field2 = source.field2; 
}

不幸的是,
base
是只读的

[编辑]
好吧,也许没那么不幸。基类和子类之间的关系是
is-a
而不是
HAS-a
。允许子类更改基类的实例,就是允许子类更改自己的引用,因为它
是-a
基类。如果确实需要此功能,那么我建议您更改继承模型以反映您真正想要做的事情

大概是这样的:

public class A
{
    public string field1;
    public string field2;
}

public class B
{
    public string field3;
    public A a;

    public void Assign(A source)
    {
        this.a = source;
    }
}
B b = new B ( new A { Field1 = "hello", Field2 = "world" } );

b.A = new A { Field1 = "hola", Field2 = "luna" };
似乎更合适,并且具有更清晰的含义和功能

        public Assign(A a)
        {
            foreach (var prop in typeof(A).GetProperties())
            {
                this.GetType().GetProperty(prop.Name).SetValue(this, prop.GetValue(a, null),null);
            }
        }
基本上,它使用反射来获取基的所有属性,并将该属性的值分配给A中存在的所有值

编辑:对于所有反对者,我现在用一个有100个整型变量的基类快速测试了这一点。然后我在一个子类中使用了这个赋值方法。运行了46毫秒。我不知道你的情况,但我完全同意。

根据MSDN,“base”只能用于以下操作:

  • 对已被另一个方法重写的基类调用方法
  • 指定在创建派生类的实例时应调用哪个基类构造函数

    • 为什么需要?通过声明新的B,CLR会自动调用这两个类的构造函数

      B myB = new B();
      
      B new具有两个类的字段。但是,除非您喜欢空值,否则应使用初始值设定项声明它们:

      public string field1 = "";
      public string field2 = string.Empty;
      

      虽然这里有很多很好的答案,但我认为正确的方法是链接构造函数:

      public class A
      {
          public string field1;
          public string field2;
      
          public A(string field1, string2 field2)
          {
               this.field1 = field1;
               this.field2 = field2;
          }
      }
      
      public class B : A
      {
          public string field3;
      
          public B(string field1, string2 field2, string field3)
              : base(field1, field2)
          {
              this.field3 = field3;
          }
      }
      

      我希望我不是唯一一个认为替换基类是一种糟糕的设计模式的人。另一种方法是用组合替换继承:

      public class A
      {
          public string Field1 { get; set; }
          public string Field2 { get; set; }
      }
      
      public class B
      {
          public A A { get; set; }
          public string Field3 { get; set; }
      
          public B(A a) { this.A = a; }
      }
      
      现在写这样的东西很简单:

      public class A
      {
          public string field1;
          public string field2;
      }
      
      public class B
      {
          public string field3;
          public A a;
      
          public void Assign(A source)
          {
              this.a = source;
          }
      }
      
      B b = new B ( new A { Field1 = "hello", Field2 = "world" } );
      
      b.A = new A { Field1 = "hola", Field2 = "luna" };
      
      错误的问题。 你显然在滥用遗产。 尝试重构它,以便将对的引用保留为成员字段。
      如果需要多态性,请考虑具有公共基类或更好的接口。

      是在对象构造期间这些字段将被初始化一次的意图,或者在对象的生命周期中可以“赋值”多次调用?如果后者,可以忽略其余部分:)/p> 安德鲁在IS-A和HAS-A之间的区别很重要;如果这种关系真的是HAS-A,那么他的构图解决方案就是一条出路

      如果IS-A关系更有意义(并且您可以修改A),那么复制构造函数可能是一个好主意:

      public class A
      {
          public string field1;
          public string field2;
      
          public A(A copyFrom)
          {
              this.field1 = copyFrom.field1;
              this.field2 = copyFrom.field2;
          }
      }
      
      public class B : A
      {
          public string field3;
      
          public B(A source)
              : base(source)
          {
          }
      }
      

      你最终不得不复制A的每个属性,但这样做的责任在于它所属的A。

      这在技术上可能可行,但这很难看,会减慢对象的初始化速度。我讨厌人们说反射速度慢。除非你处理的是性能关键的代码,否则这真的不是问题。我做过反射反映在许多类及其所有属性上的节(在包含100个表的整个DataContext类上)这根本不用花时间。呕吐!建议个人不要做那样的事情,或使用合成,而不是向他们展示如何滥用反射…我确实理解反射不是为这种访问而设计的;我也理解我们获得工具和API是为了使用它们,因此你的解决方案似乎很好。我不是马克把它作为一个答案,因为这不是我要问的,但我赞成负责任地使用这种方法。我想这就是MemberwiseClone所做的。它可能很有用,但我也不太喜欢思考。+1这确实有一种继承被用于构图的味道。我讨厌这么说,但看起来这是唯一的一种方法我可以使用:(这是一种方式,一种迂回的方式。我强烈建议使用构造函数来设置这些字段。如果一个变量对一个类来说是私有的,那么这种方式是有原因的。如果你有一个父类,你想让它的子类来操作,那么就让它的成员受到保护或者是公共的。我不认为OO是一种不好的设计模式,你的例子让OO成为私有的。)tally无用。@Nick:在很多情况下,组合可以解决继承所不能解决的问题。经典的教科书示例是,当您需要在一个类与另一个类之间进行热交换实现时,这正是作者想要做的。(续…(上一篇)由于基类是对对象实例的引用,而不仅仅是一个奇特的容器,因此不可能将一个基类替换为另一个。因此,解决作者问题的唯一合理方法是将“基类”包装在属性中。为什么您认为我的方法是错误的?这如何回答这个问题?为什么序列化相关?
          [TestMethod]
          public void TestMethod()
          {
              A a = new A();
              a.field1 = "test";
              string xml = Serialize(a);
              xml = xml.Replace("A", "B");
              B b = Deserialize(xml);
      
              Assert.AreEqual("test", b.field1);
          }
      
          public string Serialize(A a)
          {
              System.IO.StreamReader streamReader = null;
              System.IO.MemoryStream memoryStream = null;
              try
              {
                  memoryStream = new System.IO.MemoryStream();
                  XmlSerializer serializer = new XmlSerializer(typeof(A));
                  serializer.Serialize(memoryStream, a);
                  memoryStream.Seek(0, System.IO.SeekOrigin.Begin);
                  streamReader = new System.IO.StreamReader(memoryStream);
                  return streamReader.ReadToEnd();
              }
              finally
              {
                  if ((streamReader != null))
                  {
                      streamReader.Dispose();
                  }
                  if ((memoryStream != null))
                  {
                      memoryStream.Dispose();
                  }
              }
          }
      
          public static B Deserialize(string xml)
          {
              System.IO.StringReader stringReader = null;
              try
              {
                  stringReader = new System.IO.StringReader(xml);
                  XmlSerializer serializer = new XmlSerializer(typeof(B));
                  return ((B)(serializer.Deserialize(System.Xml.XmlReader.Create(stringReader))));
              }
              finally
              {
                  if ((stringReader != null))
                  {
                      stringReader.Dispose();
                  }
              }
          }