创建一个抽象函数,它根据继承者采用不同的参数
Creating an abstract function which takes different arguments depending on inheritor
我偶然发现了一个问题,我想不出一个好的解决方法。
我的程序中有一些对象需要在发生某些事件时重新初始化。我需要重新初始化的对象是抽象 class.
的子 classes
虽然这似乎是一个糟糕的方法,但我决定在抽象 class 中有一个抽象的重新初始化函数,并让所有子classes 实现该函数。但是现在有一个问题,每个子 class 在它们的构造函数中采用不同的参数。
我的最小示例如下所示:
abstract class Base
{
public abstract void Init(/* Some parameter */);
}
class SubA : Base
{
public SubA(int a)
{
Init();
}
public override void Init(int a)
{
//do stuff with int
}
}
class SubB : Base
{
public SubB(string b)
{
Init();
}
public override void Init(string b)
{
//do stuff with string
}
}
class Program
{
static void Main(string[] args)
{
List<Base> stuff = new List<Base>()
{
new SubA(65),
new SubB("B")
};
foreach (var s in stuff)
{
s.Init();
}
}
}`
我确实相信这个解决方案有代码味道,所以欢迎任何避免这种情况的建议。如果需要任何其他信息来帮助我,请告诉我。
我认为您可能需要改用接口。
public interface IBase
{
void Init();
}
public class SubA : IBase
{
private int _a;
public SubA(int a)
{
_a = a;
}
public void Init()
{
// do stuff with _a
}
}
public class SubB : IBase
{
private string _s;
public SubB(string s)
{
_s = s;
}
public void Init()
{
// do stuff with _s
}
}
public class SubC : IBase
{
private int _a;
private string _s;
public SubC(int a, string s)
{
_a = a;
_s = s;
}
public void Init()
{
// do stuff with _a and _s
}
}
class Program
{
static void Main(string[] args)
{
List<IBase> stuff = new List<IBase>()
{
new SubA(65),
new SubB("B"),
new SubC(100, "Z"),
};
foreach (IBase sub in stuff)
{
sub.Init();
}
}
}
好吧,解决方案很简单,只需在私有字段中声明 specific 变量,然后在 paramaterless Init
方法中使用这些字段,像这样:
class SubA : Base
{
private int _a;
public SubA(int a)
{
_a = a;
Init();
}
public override void Init()
{
//do stuff with int _a
}
}
class SubB : Base
{
private string _b;
public SubB(string b)
{
_b = b;
Init();
}
public override void Init()
{
//do stuff with string _b
}
}
此外,您可以改为抽象 class 接口,因此实现它的 classes 也将能够从其他基础 classes 继承。
令人困惑的是,您为什么要以一种循环方式重新初始化项目集合,使每个项目都获得一个新值。您的代码有很多问题,但我会尝试解释它们,因为您的示例无法编译。
首先,如果你想在子class SubA
中调用Init,你必须像这样在SubA
中实现它。
abstract class Base
{
public abstract void Init()
}
class SubA : Base
{
public SubA(int a)
{
this.Init();
}
public override void Init()
{
// do stuff
}
public void Init(int a)
{
//do stuff with int
}
}
如果你想调用init而不覆盖它,那么抽象基class需要这样实现
abstract class Base
{
public void Init()
{
//do stuff in the implementation by the abstract class
}
}
class SubA : Base
{
public SubA(int a)
{
this.Init();
}
public void Init(int a)
{
//do stuff with int
}
}
看来您想要的是能够重新初始化 Base
的任何子 class,并可选择让子 class 执行自定义初始化.
如果你想让它们重新初始化到它们的原始状态,你可以将它们的原始状态存储在实例中,并使用被覆盖的 Init() 来恢复。
class Foo : Base
{
private int _iOrig;
private string _sOrig;
public int i { get; set; }
public string s { get; set; }
public Foo(int i, string s)
{
this.i = i;
this._iOrig = i;
this.s = s;
this._sOrig = s;
}
public override void Init()
{
this.i = _iOrig;
this.s = _sOrig;
}
}
如果一切都将是抽象的,您甚至可以考虑使用接口。
如果您想使用外部数据重新初始化它们,您可以遍历它们并检查它们是什么类型,然后调用它们自己的 Init
方法,这意味着 Base
不会需要有一个abstract Init()
,而子classes可以实现他们想要的任何东西。 (虽然这似乎不是你想要的)。
这可以使用转换检查在循环中完成。
private void InitAll(IEnumerable<Base> collection)
{
foreach(Base b in collection)
{
var sa = b as SubA;
if(sa != null)
{
sa.Init(getInt());
continue;
}
var sb = b as SubB;
if (sb != null)
{
sb.Init(getString());
continue;
}
}
}
我偶然发现了一个问题,我想不出一个好的解决方法。
我的程序中有一些对象需要在发生某些事件时重新初始化。我需要重新初始化的对象是抽象 class.
的子 classes虽然这似乎是一个糟糕的方法,但我决定在抽象 class 中有一个抽象的重新初始化函数,并让所有子classes 实现该函数。但是现在有一个问题,每个子 class 在它们的构造函数中采用不同的参数。
我的最小示例如下所示:
abstract class Base
{
public abstract void Init(/* Some parameter */);
}
class SubA : Base
{
public SubA(int a)
{
Init();
}
public override void Init(int a)
{
//do stuff with int
}
}
class SubB : Base
{
public SubB(string b)
{
Init();
}
public override void Init(string b)
{
//do stuff with string
}
}
class Program
{
static void Main(string[] args)
{
List<Base> stuff = new List<Base>()
{
new SubA(65),
new SubB("B")
};
foreach (var s in stuff)
{
s.Init();
}
}
}`
我确实相信这个解决方案有代码味道,所以欢迎任何避免这种情况的建议。如果需要任何其他信息来帮助我,请告诉我。
我认为您可能需要改用接口。
public interface IBase
{
void Init();
}
public class SubA : IBase
{
private int _a;
public SubA(int a)
{
_a = a;
}
public void Init()
{
// do stuff with _a
}
}
public class SubB : IBase
{
private string _s;
public SubB(string s)
{
_s = s;
}
public void Init()
{
// do stuff with _s
}
}
public class SubC : IBase
{
private int _a;
private string _s;
public SubC(int a, string s)
{
_a = a;
_s = s;
}
public void Init()
{
// do stuff with _a and _s
}
}
class Program
{
static void Main(string[] args)
{
List<IBase> stuff = new List<IBase>()
{
new SubA(65),
new SubB("B"),
new SubC(100, "Z"),
};
foreach (IBase sub in stuff)
{
sub.Init();
}
}
}
好吧,解决方案很简单,只需在私有字段中声明 specific 变量,然后在 paramaterless Init
方法中使用这些字段,像这样:
class SubA : Base
{
private int _a;
public SubA(int a)
{
_a = a;
Init();
}
public override void Init()
{
//do stuff with int _a
}
}
class SubB : Base
{
private string _b;
public SubB(string b)
{
_b = b;
Init();
}
public override void Init()
{
//do stuff with string _b
}
}
此外,您可以改为抽象 class 接口,因此实现它的 classes 也将能够从其他基础 classes 继承。
令人困惑的是,您为什么要以一种循环方式重新初始化项目集合,使每个项目都获得一个新值。您的代码有很多问题,但我会尝试解释它们,因为您的示例无法编译。
首先,如果你想在子class SubA
中调用Init,你必须像这样在SubA
中实现它。
abstract class Base
{
public abstract void Init()
}
class SubA : Base
{
public SubA(int a)
{
this.Init();
}
public override void Init()
{
// do stuff
}
public void Init(int a)
{
//do stuff with int
}
}
如果你想调用init而不覆盖它,那么抽象基class需要这样实现
abstract class Base
{
public void Init()
{
//do stuff in the implementation by the abstract class
}
}
class SubA : Base
{
public SubA(int a)
{
this.Init();
}
public void Init(int a)
{
//do stuff with int
}
}
看来您想要的是能够重新初始化 Base
的任何子 class,并可选择让子 class 执行自定义初始化.
如果你想让它们重新初始化到它们的原始状态,你可以将它们的原始状态存储在实例中,并使用被覆盖的 Init() 来恢复。
class Foo : Base
{
private int _iOrig;
private string _sOrig;
public int i { get; set; }
public string s { get; set; }
public Foo(int i, string s)
{
this.i = i;
this._iOrig = i;
this.s = s;
this._sOrig = s;
}
public override void Init()
{
this.i = _iOrig;
this.s = _sOrig;
}
}
如果一切都将是抽象的,您甚至可以考虑使用接口。
如果您想使用外部数据重新初始化它们,您可以遍历它们并检查它们是什么类型,然后调用它们自己的 Init
方法,这意味着 Base
不会需要有一个abstract Init()
,而子classes可以实现他们想要的任何东西。 (虽然这似乎不是你想要的)。
这可以使用转换检查在循环中完成。
private void InitAll(IEnumerable<Base> collection)
{
foreach(Base b in collection)
{
var sa = b as SubA;
if(sa != null)
{
sa.Init(getInt());
continue;
}
var sb = b as SubB;
if (sb != null)
{
sb.Init(getString());
continue;
}
}
}