繁体   English   中英

基类对象作为派生类的参数

[英]Base class object as argument for derived class

(简化)场景:

public class BaseClass
{
    public int BaseClassInt {get; set;}

    public BaseClass(int pBaseClassInt)
    { this.BaseClassInt = pBaseClassInt; }

}

public class DerivedClass : BaseClass
{
    public int DerivedClassInt {get; set;}

    public DerivedClass (int pBaseClassInt, int pDerivedClassInt) : base(pBaseClassInt)
    { this.DerivedClassInt = pDerivedClassInt; }

}

如果我想实例化一个 DerivedClass 对象,我必须传递创建 BaseClass 对象和 DerivedClass 对象所需的所有参数。 同样对于每个 BaseClass 构造函数,我必须(至少在我的具体情况下应该)在派生类中提供一个具有相同参数的构造函数,以及派生类属性的参数。 然后,如果我更改或删除基类中的构造函数,则必须更改或删除派生类中的相应构造函数。

我想知道是否可以为接受基类对象作为参数的派生类使用构造函数:

public DerivedClass(BaseClass pBaseClassObejct, int pDerivedClassInt)
{
    // to make clear what I intend to do - looks silly of course
    this = (DerivedClass)pBaseClassObject;
    this.DerivedClassInt = pDerivedClassInt;
}

这可以称为:

DerivedClass DerivedClassObject = new DerivedClass((new BaseClass(1),2);

如果基类中的构造函数会改变,我就不必为派生类担心。 有没有办法实现这一目标?

想一想这一行:

this = (DerivedClass) pBaseClassObject;

让我们忽略您不能直接以这种方式设置this事实,并专注于其余部分。

想象一下GiraffeElephant都是非洲动物的实现:

// By extension, ellie is also an AfricanAnimal    
Elephant ellie = new Elephant(); 

// assume ellie is passed in as a param here (she can 
// be, because she is an AfricanAnimal after all!):
public Giraffe(AfricanAnimal ellie) 
{
    this = (Giraffe) ellie; // Can't do this!
}

你不能(也不想)强迫 ellie 成为长颈鹿,因为长颈鹿可能具有 ellie 缺乏的特性等,而 ellie 可能具有长颈鹿没有的特性。 然而,在那里使用AfricanAnimal作为参数类型,就可以做到这一点。

注意:可以编写该代码并传入 Giraffe,一切都会好起来的,但话说回来,这毫无意义; 那么你不妨使用长颈鹿类型作为参数。

如果你用一个实例变量替换this ,你将能够使用如下内容进行编译......

public Giraffe(AfricanAnimal ellie) 
{
    this.varOfTypeGiraffe = (Giraffe) ellie; 
}

...但是一旦您使用Elephant作为参数运行它,您将得到类似于以下内容的异常:

InvalidCastException:无法将“大象”类型的对象转换为“长颈鹿”类型。

TL;DR:这是个坏主意。 甚至不要尝试。

您不能在任何派生方法(包括派生构造函数)的主体内部运行基构造函数。 即使可以,基础实例也不会保留有关使用哪个构造函数来实例化它的任何信息,因此无法知道应该调用哪个基础构造函数。

以上是指基本构造函数可能修改与基类不直接相关的应用程序状态的一般情况(例如,通过更改某处静态字段的值)。 可以使用反射将属性值从基础实例复制到正在创建的派生实例,但这实际上是行不通的,因为

  1. 它要求您首先创建一个基础实例——如果基础是abstract ,或者创建一个有副作用怎么办?
  2. 您需要保证基础构造函数不会修改应用程序状态。 但这里的目标是独立于基础构造函数的作用,所以你又回到了原点。

不,这是不可能的,也不应该是,因为它没有意义。

如果可能并且您删除/更改了基类构造函数,您仍然需要更改创建基类对象的代码,您将用作派生类构造函数的参数。

此外,并非所有基类都是具体的。 您将无法创建抽象基类,对吗?

此功能不可用。 我想你想要的有点像这样:

假设 C# 有一个关键字allbaseargs并允许这样的代码:

public class DerivedClass : BaseClass
{
  public int DerivedClassInt { get; set; }

  public DerivedClass (allbaseargs, int pDerivedClassInt)
    : base(allbaseargs)
  {
    DerivedClassInt = pDerivedClassInt;
  }
}

那么这只有在BaseClass只有一个(可访问的)实例构造函数时才能工作。

然后编译器应该检查唯一的基本构造函数,并用该构造函数的参数替换神奇的单词allbaseargs

但是,C# 没有此功能,您必须手动编写所有内容,包括在构造函数签名更改时更改所有派生类的 all : base(...)调用。

允许有签名:

public DerivedClass(BaseClass pBaseClassObejct, int DerivedClassInt)

就像您建议的那样,但您无法轻松链接: base(...) 您必须为BaseClass配备一个构造BaseClass ,该构造函数接受另一个实例并将所有“状态”(所有实例属性和字段等)从另一个实例复制到“ this ”。 我不推荐该解决方案。

这可能有帮助!

解决方案 A:创建 Inherit 而不是 base!

public static class Test
{
    public static T Foo<T>(string text, int num) where T : BaseClass
    {
        T @base = (T)Activator.CreateInstance(typeof(T), new object[] { text, num });
        //...
        return @base;
    }

    public static void Main()
    {
        InheritClass inherit = Foo<InheritClass>("Hi there", 10);
    }
}

方案B:复制基类继承

public static class Test
{
    public static TInherit As<TBase, TInherit>(this TBase @this) where TInherit : TBase
    {
        var type = typeof(TInherit);
        var instance = Activator.CreateInstance(type);
        foreach (var property in type.GetProperties())
            if (property.CanWrite)
                property.SetValue(instance, property.GetValue(@this, null), null);
        return (TInherit)instance;
    }
    public static BaseClass Foo(string text, int num)
    {
        BaseClass @base = new BaseClass(text, num);
        //...
        return @base;
    }

    public static void Main()
    {
        InheritClass inherit = Foo("Hi there", 10).As<BaseClass, InheritClass>();
    }
}

注意:您可以在此处找到简单的“As()”,但我更喜欢我的(其中 Inherit : TBase),它更安全并且支持将 base 转换为继承类的继承。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM