C# 基类中的方法如何根据调用它的对象的类型返回更派生的对象?

C# 基类中的方法如何根据调用它的对象的类型返回更派生的对象?,c#,oop,reflection,C#,Oop,Reflection,假设您有两个类,如下例所示 如何修改SplitObject,使其始终返回t类型的对象,例如在Main()中,它应该返回DerivedClass类型的对象 我猜解决方案应该包括反思?我还没有学到任何关于反思的知识,所以我不知道这是怎么回事 public class BaseClass { float _foo; public BaseClass(float foo){_foo = foo} public BaseClass SplitObject() {

假设您有两个类,如下例所示

如何修改SplitObject,使其始终返回t类型的对象,例如在Main()中,它应该返回DerivedClass类型的对象

我猜解决方案应该包括反思?我还没有学到任何关于反思的知识,所以我不知道这是怎么回事

public class BaseClass
{
    float _foo;

    public BaseClass(float foo){_foo = foo}

    public BaseClass SplitObject()
    {
        Type t = GetType();

        // Do something with t 

        _foo = _foo/2f;
        return new BaseClass(_foo); // I want to construct an 
                                   // object of type t instead 
                                  // of type BaseClass
    }
}

public class DerivedClass : BaseClass
{
    public DerivedClass(float foo) : base(foo){}
}

class Program
{
    static void Main() 
    {
        BaseClass foo = new DerivedClass(1f);

        BaseClass bar = foo.SplitObject(); // should return a DerivedObject
    }
}
无需反射——只需将
SplitObject()
设为虚拟,并在派生类中以不同的方式实现它

另一种选择是将拆分行为提取到接口中,例如
ISplittable


}

如果您真的想使用反射,可以执行以下操作:

return (BaseClass)Activator.CreateInstance(GetType(), _foo);
//... Base class:   

public BaseClass SplitObject()
{      
    _foo = _foo / 2f;
    return NewInstance(_foo);
}

protected virtual BaseClass NewInstance(float foo)
{
   return new BaseClass(foo);   
}

//... Derived class:

protected override BaseClass NewInstance(float foo)
{
   return new DerivedClass(foo);
}
当然,现在有一个隐式约定,所有派生类都必须实现这样的构造函数。遗憾的是,在当前类型系统中无法指定此类合同;因此,在编译时不会捕获违规行为。按照埃拉斯的想法会更好。我会这样做:

return (BaseClass)Activator.CreateInstance(GetType(), _foo);
//... Base class:   

public BaseClass SplitObject()
{      
    _foo = _foo / 2f;
    return NewInstance(_foo);
}

protected virtual BaseClass NewInstance(float foo)
{
   return new BaseClass(foo);   
}

//... Derived class:

protected override BaseClass NewInstance(float foo)
{
   return new DerivedClass(foo);
}

如果只希望代码显示在一个位置(更好地进行维护,尤其是在有许多派生类型的情况下),则需要使用反射:

  public class BaseClass
{
    float _foo;

    public BaseClass(float foo){_foo = foo;}

    public BaseClass SplitObject()
    {
        Type t = GetType();
        _foo = _foo / 2f;

        //Find the constructor that accepts float type and invoke it:
        System.Reflection.ConstructorInfo ci = t.GetConstructor(new Type[]{typeof(float)});
        object o=ci.Invoke(new object[]{_foo});

        return (BaseClass)o; 
    }
}

public class DerivedClass : BaseClass
{
    public DerivedClass(float foo) : base(foo) { }
}

class Program
{
    static void Main()
    {
        BaseClass foo = new DerivedClass(1f);

       //Cast the BaseClass to DerivedClass:
        DerivedClass bar = (DerivedClass)foo.SplitObject(); 
    }
}

我不想使用虚拟方法,因为这涉及到复制代码。我通常不喜欢任何需要我在多个地方修改的东西,因为它们都在有效地使用相同的代码!我希望能够编写一个方法,并让它对任何对象都能同样工作。然而,我可能会使用虚拟方法来避免由于需要特定的构造函数签名而使事情过于复杂。我选择了你的答案,因为它是一个很好的简短代码。