是否可以使用显式类型转换将基类对象分配给派生类引用?

Mad*_*hik 73 c# casting explicit base-class derived-class

是否可以使用C#中的显式类型转换将基类对象分配给派生类引用?

我试过它,它会产生运行时错误.

Jon*_*eet 88

否.对派生类的引用实际上必须引用派生类的实例(或null).否则你会怎么期望它表现出来?

例如:

object o = new object();
string s = (string) o;
int i = s.Length; // What can this sensibly do?
Run Code Online (Sandbox Code Playgroud)

如果您希望能够将基类型的实例转换为派生类型,我建议您编写一个方法来创建适当的派生类型实例.或者再次查看继承树并尝试重新设计,这样您就不需要首先执行此操作.

  • @Mike:代码编译得很好.它虽然在执行时间倒下:) (67认同)
  • 这是第一个:Jon Skeet编写的代码无法编译! (33认同)
  • @Akie:不,它创建一个类型为`Derived`的对象,但是你可以将`Derived`引用视为`Base`引用. (3认同)
  • @Akie:是的,一个创建一个`Base`实例,另一个创建一个`Derived`实例.如果你在```上调用了一个在`Derived`中被覆盖的虚方法,如果你有一个'Derived`实例,你会看到`Derived`行为.但是在Stack Overflow评论主题中深入研究细节并不合适 - 你应该真正阅读一本好的C#书或教程,因为这是非常基本的东西. (3认同)

Mic*_*ent 41

不,这是不可能的,因为将它分配给派生类引用就像是说"基类是派生类的完全能力替代,它可以完成派生类可以做的所有事情",这是不正确的,因为派生类一般提供比他们的基类更多的功能(至少,这是继承背后的想法).

您可以在派生类中编写构造函数,将基类对象作为参数,复制值.

像这样的东西:

public class Base {
    public int Data;

    public void DoStuff() {
        // Do stuff with data
    }
}

public class Derived : Base {
    public int OtherData;

    public Derived(Base b) {
        this.Data = b.Data;
        OtherData = 0; // default value
    }

    public void DoOtherStuff() {
        // Do some other stuff
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您将复制基础对象并获取具有派生成员的默认值的功能齐全的派生类对象.这样你也可以避免Jon Skeet指出的问题:

Base b = new Base();//base class
Derived d = new Derived();//derived class

b.DoStuff();    // OK
d.DoStuff();    // Also OK
b.DoOtherStuff();    // Won't work!
d.DoOtherStuff();    // OK

d = new Derived(b);  // Copy construct a Derived with values of b
d.DoOtherStuff();    // Now works!
Run Code Online (Sandbox Code Playgroud)


Mar*_*son 20

我遇到了这个问题并通过添加一个带有类型参数的方法并将当前对象转换为该类型来解决它.

public TA As<TA>() where TA : Base
{
    var type = typeof (TA);
    var instance = Activator.CreateInstance(type);

     PropertyInfo[] properties = type.GetProperties();
     foreach (var property in properties)
     {
         property.SetValue(instance, property.GetValue(this, null), null);
     }

     return (TA)instance;
}
Run Code Online (Sandbox Code Playgroud)

这意味着您可以在代码中使用它,如下所示:

var base = new Base();
base.Data = 1;
var derived = base.As<Derived>();
Console.Write(derived.Data); // Would output 1
Run Code Online (Sandbox Code Playgroud)


MEC*_*MEC 10

正如许多其他人所回答的那样.

当我需要使用基类型作为派生类型时,我在那些不幸的场合使用以下代码.是的,它违反了Liskov替代原则(LSP),是的,大多数时候我们赞成合成而不是继承.Markus Knappen Johansson的道具,其原始答案基于此.

这个代码在基类中:

    public T As<T>()
    {
        var type = typeof(T);
        var instance = Activator.CreateInstance(type);

        if (type.BaseType != null)
        {
            var properties = type.BaseType.GetProperties();
            foreach (var property in properties)
                if (property.CanWrite)
                    property.SetValue(instance, property.GetValue(this, null), null);
        }

        return (T) instance;
    }
Run Code Online (Sandbox Code Playgroud)

允许:

    derivedObject = baseObect.As<derivedType>()
Run Code Online (Sandbox Code Playgroud)

由于它使用反射,因此它"昂贵".相应地使用.


Jes*_*ans 10

使用 JsonConvert 的解决方案(而不是类型转换)

今天,我面临着同样的问题,我发现了一个简单而快速的解决问题的方法使用JsonConvert

var base = new BaseClass();
var json = JsonConvert.SerializeObject(base);
DerivedClass derived = JsonConvert.DeserializeObject<DerivedClass>(json);
Run Code Online (Sandbox Code Playgroud)

  • 天才!!!这是一个很好的答案,谢谢! (3认同)

Kir*_*san 6

在 c# 9.0 中,您可以尝试使用记录来实现此目的。它们具有复制所有字段的默认复制构造函数 - 无需对所有字段使用反射/构造函数。

public record BaseR
{
   public string Prop1 { get; set; }
}

public record DerivedR : BaseR
{
   public DerivedR(BaseR baseR) : base(baseR) { }
   public string Prop2 { get; set; }
}

var baseR = new BaseR { Prop1 = "base prob" };
var derivedR = new DerivedR(baseR) { Prop2 = "new prop" };
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


ybo*_*ybo 5

不,这是不可能的,因此您的运行时错误.

但是,您可以将派生类的实例分配给基类类型的变量.


Mah*_*vcs 5

正如这里的所有人所说,这不可能直接实现。

我更喜欢并且很干净的方法是使用像AutoMapper这样的对象映射器。

它将执行自动将属性从一个实例复制到另一个实例(不一定是相同类型)的任务。