简体   繁体   English

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

[英]Base class object as argument for derived class

(Simplified) Scenario: (简化)场景:

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; }

}

If I want to instantiate a DerivedClass-object I have to pass all arguments required to create a BaseClass-object and a DerivedClass-object.如果我想实例化一个 DerivedClass 对象,我必须传递创建 BaseClass 对象和 DerivedClass 对象所需的所有参数。 Also for every BaseClass-constructor I have to (at least should in my concrete case) provide a constructor with the same arguments in the derived class, plus arguments for the derived class properties.同样对于每个 BaseClass 构造函数,我必须(至少在我的具体情况下应该)在派生类中提供一个具有相同参数的构造函数,以及派生类属性的参数。 Then, if I change or delete a constructor in the base class I have to change or delete the corresponding contructor in the derived class(es).然后,如果我更改或删除基类中的构造函数,则必须更改或删除派生类中的相应构造函数。

I wonder if it is possible to use a constructor for the derived class which accepts a base class-object as an argument:我想知道是否可以为接受基类对象作为参数的派生类使用构造函数:

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

This could be called:这可以称为:

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

If constructors in the base class would change, I wouldn´t have to mind it for the derived class.如果基类中的构造函数会改变,我就不必为派生类担心。 Is there any way to achieve this?有没有办法实现这一目标?

Think about this line for a moment:想一想这一行:

this = (DerivedClass) pBaseClassObject;

Let's ignore the fact that you cant set this directly that way, and focus on the rest.让我们忽略您不能直接以这种方式设置this事实,并专注于其余部分。

Imagine Giraffe and Elephant are both implementations of AfricanAnimal:想象一下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!
}

You can't (and would not want to) force ellie into being a giraffe, because a giraffe may have properties etc. that ellie lacks, and ellie may have properties that Giraffes don't have.你不能(也不想)强迫 ellie 成为长颈鹿,因为长颈鹿可能具有 ellie 缺乏的特性等,而 ellie 可能具有长颈鹿没有的特性。 Yet, using an AfricanAnimal as your parameter type there, would allow for just that.然而,在那里使用AfricanAnimal作为参数类型,就可以做到这一点。

Note: You could write that code and pass a Giraffe in, and all would be fine, but then again, that makes little sense;注意:可以编写该代码并传入 Giraffe,一切都会好起来的,但话说回来,这毫无意义; then you might as well use the Giraffe type as the parameter.那么你不妨使用长颈鹿类型作为参数。

If you replace this with an instance variable, you would be able to compile with something like the following...如果你用一个实例变量替换this ,你将能够使用如下内容进行编译......

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

... but as soon as you run it with an Elephant as aa prameter, you will get an exception similar to: ...但是一旦您使用Elephant作为参数运行它,您将得到类似于以下内容的异常:

InvalidCastException: Unable to cast object of type 'Elephant' to type 'Giraffe'. InvalidCastException:无法将“大象”类型的对象转换为“长颈鹿”类型。

TL;DR: This is a bad idea. TL;DR:这是个坏主意。 Don't even try.甚至不要尝试。

You cannot make a base constructor run from inside the body of any derived method (including the derived constructor).您不能在任何派生方法(包括派生构造函数)的主体内部运行基构造函数。 Even if you could, a base instance would not have retained any information about which constructor was used to instantiate it so there would be no way to know which base constructor should be called.即使可以,基础实例也不会保留有关使用哪个构造函数来实例化它的任何信息,因此无法知道应该调用哪个基础构造函数。

The above refers to the general case where a base constructor can potentially modify application state not directly related to the base class (eg by changing the value of static fields somewhere).以上是指基本构造函数可能修改与基类不直接相关的应用程序状态的一般情况(例如,通过更改某处静态字段的值)。 You could use reflection to copy property values from a base instance to the derived instance being created, but this is practically unworkable because可以使用反射将属性值从基础实例复制到正在创建的派生实例,但这实际上是行不通的,因为

  1. It requires that you create a base instance in the first place -- what if the base is abstract , or if creating one has side effects?它要求您首先创建一个基础实例——如果基础是abstract ,或者创建一个有副作用怎么办?
  2. You need a guarantee that the base constructor does not modify application state.您需要保证基础构造函数不会修改应用程序状态。 But the aim here is to be independent of what the base constructors do, so you are back to square one.但这里的目标是独立于基础构造函数的作用,所以你又回到了原点。

No, that is not possible and should not be, because it doesn't make sense.不,这是不可能的,也不应该是,因为它没有意义。

If it was possible and you deleted/changed the base class constructor, you would still need to change the code which creates the base class object that you would use as an argument to the derived class constructor.如果可能并且您删除/更改了基类构造函数,您仍然需要更改创建基类对象的代码,您将用作派生类构造函数的参数。

Also, not all base classes are concrete.此外,并非所有基类都是具体的。 You would not be able to create an abstract base class, right?您将无法创建抽象基类,对吗?

This feature is not available.此功能不可用。 I think what you want is a little like this:我想你想要的有点像这样:

Suppose C# had a keyword allbaseargs and allowed code like this:假设 C# 有一个关键字allbaseargs并允许这样的代码:

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

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

Then this could only work if BaseClass had only one (accessible) instance constructor .那么这只有在BaseClass只有一个(可访问的)实例构造函数时才能工作。

The compiler should then examine the sole base constructor and substitute the magical word allbaseargs with the parameters of that constructor.然后编译器应该检查唯一的基本构造函数,并用该构造函数的参数替换神奇的单词allbaseargs

However, C# does not have this feature, and you would have to hand-code everything, which includes changeing all : base(...) calls of all derived classes when the constructor signature changes.但是,C# 没有此功能,您必须手动编写所有内容,包括在构造函数签名更改时更改所有派生类的 all : base(...)调用。

It is allowed to have the signature:允许有签名:

public DerivedClass(BaseClass pBaseClassObejct, int DerivedClassInt)

like you suggest, but you would not be able to chain the : base(...) easily.就像您建议的那样,但您无法轻松链接: base(...) You would have to equip BaseClass with a construtor that took another instance in and copied all "state" (all instance properties and fields and such) from that other instance to " this ".您必须为BaseClass配备一个构造BaseClass ,该构造函数接受另一个实例并将所有“状态”(所有实例属性和字段等)从另一个实例复制到“ this ”。 I do not recommend that solution.我不推荐该解决方案。

This might be help!这可能有帮助!

Solution A: Create Inherit instead of base!解决方案 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);
    }
}

Solution B: Copy base to inherit方案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>();
    }
}

Notes: you can have simple 'As()' found here , but i prefer mine (where Inherit : TBase), where it's more safe and support converting base to inherit of inherit class.注意:您可以在此处找到简单的“As()”,但我更喜欢我的(其中 Inherit : TBase),它更安全并且支持将 base 转换为继承类的继承。

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

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