![](/img/trans.png)
[英]“this” keyword type when called on an object of derived class from base class
[英]How can a method in a base class return a more derived object based on the type of the object it is called on?
假設您有兩個類,如下例所示。
您將如何修改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()
設為虛擬,並在派生類中以不同的方式實現即可。
另一個選擇是將Split行為提取到接口中,例如ISplittable<T>
public class BaseClass
{
public virtual BaseClass SplitObject()
{
BaseClass splitObject = new BaseClass();
//initialize the split object
return splitObject;
}
}
public class DerivedClass : BaseClass
{
public override BaseClass SplitObject()
{
DerivedClass derivedSplitObject = new DerivedClass();
//initialize the derived split object
return derivedSplitObject;
}
}
}
如果您真的想使用反射,則可以執行以下操作:
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();
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.