C# 很难结合使用基本构造函数和非静态字段
我被这个问题困扰了太多次,所以我决定与大家分享并看看你们的想法,让我们看看以下(愚蠢的)例子: 我想问的是: Q1:为什么base()参数必须是静态的 Q2:如果像我的示例中那样,我们希望将非静态字段或方法与对基本构造函数的调用结合起来,会怎么样?什么是最面向对象的方法来实现这一点 注意:尽量不要给出像“不要使用底座”这样的绷带解决方案,因为可能会有更复杂的情况,使用底座是不可避免的,所以我正在寻找一个合理、设计良好的解决方案 谢谢 更新: 我的例子太容易破解,所以我觉得我学的还不够,所以让我们试着再举一个(相当愚蠢的)例子: HashFunc(E)中的公共委托; 公共接口哈希表{ 空白插入(E); 布尔·伊斯梅尔(E); } 类HashArray:HashTable,其中E:IComparable{ 私人E[]a; 私人住宅; 公共只读INTN; 公共整数大小{ 获取{返回n;} } HashFunc散列; 公共哈希数组(int m,HashFunc哈希){ n=2*m; a=新的E[n]; take=新bool[n]; 对于(int i=0;i Q1:为什么base()参数必须是静态的 它们必须是静态的,因为在构造函数调用时还没有定义实例(该定义是“正在进行的”) 问题2:如果像在我的示例中一样,我们希望将非静态字段或方法与对基构造函数的调用相结合,那会怎么样?最适合OOP的方法是什么 面向对象的方法只是简单的方法重写C# 很难结合使用基本构造函数和非静态字段,c#,constructor,C#,Constructor,我被这个问题困扰了太多次,所以我决定与大家分享并看看你们的想法,让我们看看以下(愚蠢的)例子: 我想问的是: Q1:为什么base()参数必须是静态的 Q2:如果像我的示例中那样,我们希望将非静态字段或方法与对基本构造函数的调用结合起来,会怎么样?什么是最面向对象的方法来实现这一点 注意:尽量不要给出像“不要使用底座”这样的绷带解决方案,因为可能会有更复杂的情况,使用底座是不可避免的,所以我正在寻找一个合理、设计良好的解决方案 谢谢 更新: 我的例子太容易破解,所以我觉得我学的还不够,所以让我们
class Runner
{
ToRun tr;
public Runner(ToRun f)
{
tr=f;
}
public virtual void Run()
{
tr();
}
}
class CountingRunner : Runner {
int i;
public CountingRunner(ToRun f) : base(f) {
i=0;
}
public override void Run() {
i++;
base.Run();
}
}
关于Q1和Q2,参数不是必须是静态的,而是必须在调用时可以访问参数 基本构造函数在本地构造函数之前被调用,这就是为什么不能使用
这个成员作为参数,以及为什么不应该调用虚拟调用的原因
不完全确定最终目标是什么,但它确实类似于一个。这就是你想要的:
class Runner {
protected event Action _toRun;
public Runner() {
}
public void Run() {
var r = _toRun;
if (r != null)
_toRun();
}
}
class CountingRunner : Runner {
int i;
public CountingRunner(Action f) : base() {
_toRun += f;
}
public void inc() {
i++;
}
}
编辑
对于使用哈希表的特定示例,此问题可以通过语言的设计来解决。只需对哈希表的元素调用GetHashCode()即可确定它们的哈希代码。传递哈希函数不需要实现
class HashArray<E> : HashTable<E> where E : IComparable<E> {
private E[] a;
private bool[] taken;
public readonly int n;
public int size {
get { return n; }
}
public HashArray(int m) {
n=2*m;
a=new E[n];
taken=new bool[n];
for (int i=0 ; i<n ; i++) taken[i]=false;
}
public void insert(E e) {
int index= GetSpecialHashCode(e)%n;
int i;
for (i=index ; i<n && taken[i]!=false ; ++i) ;
if (i>=n)
for (i=0 ; i<index && taken[i]!=false ; ++i) ;
if (i>=index) return;
taken[i]=true;
a[i]=e;
}
public bool isMember(E e) {
int i= GetSpecialHashCode(e)%n;
for ( ; i<n && taken[i]!=false && a[i].CompareTo(e)!=0 ; ++i );
if (i>=n || taken[i]==false) return false;
return true;
}
protected virtual int GetSpecialHashCode(E item) {
return item.GetHashCode();
}
}
要回答您更一般的问题“我应该如何将操作实例数据的函数发送到基类,”您应该在lambda表达式中捕获实例变量,并将其发送到基类,或者考虑基类不需要访问派生类的实例函数的设计。
一种这样的设计是让函数在基类中有一个纯虚拟调用。这需要派生类来实现虚拟调用,以便进行实例化。因此,这里有一个abstract int GetHashCode(E项)
函数,并在子类中重写它。同样,在这种特定情况下,该语言使用为所有类型定义的虚拟GetHashCode()
函数为您执行此操作
下面是一个非抽象示例(不需要派生类来重写哈希函数)
class HashArray:HashTable,其中E:IComparable{
私人E[]a;
私人住宅;
公共只读INTN;
公共整数大小{
获取{返回n;}
}
公共哈希数组(int m){
n=2*m;
a=新的E[n];
take=新bool[n];
对于(int i=0;i对于您的最后一个示例,我认为这是可行的:
class HashArrayInt : HashArray<int> {
public HashArrayInt(int n) : base (n,i => HashFunc(i,n)) {
}
private static int HashFunc(int i, int n) {
return (i%n);// n is a non static field, every hash table has its own size!
}
}
类HashArrayInt:HashArray{
公共HashArrayInt(int n):基(n,i=>HashFunc(i,n)){
}
私有静态int HashFunc(int i,int n){
return(i%n);//n是一个非静态字段,每个哈希表都有自己的大小!
}
}
如果没有,您可以执行以下操作:
class HashFuncProvider {
private int n;
public HashFuncProvider(int n){
this.n = n;
}
public int HashFunc(int i) {
return (i%n);
}
}
class HashArrayInt : HashArray<int> {
public HashArrayInt(int n) : base (n, new HashFuncProvider(n).HashFunc) {
}
}
类HashFuncProvider{
私人int n;
公共哈希函数提供程序(int n){
这个,n=n;
}
公共整数HashFunc(整数i){
返回(i%n);
}
}
类HashArrayInt:HashArray{
公共HashArrayInt(int n):基(n,新的HashFuncProvider(n).HashFunc){
}
}
你可以将构造函数设置为私有的,并使用静态的Create
方法作为构造函数,但你将拥有更多的能力来了解如何从那里开始工作。只需将n作为散列函数的一个参数?是的,这是我想做的,但委托是由讲师指定的,因此我们无法更改它。另外,谁说有hash函数和hash大小之间没有连接?因此更改hash委托可能会强制定义n在何处是冗余的…对于初学者来说,has函数不是真正的i%n。它只是i.n是基类的私有成员变量。它不能是基类提供的hash函数的一部分,因为它不可访问e(而且不应该是)对于基类。我在我的答案中添加了一个编辑。+1表示正确的ansewr,但是从CountingRunner
@MichaelGraczyk中删除ToRun tr
成员,Runner
中需要它……您将ToRun
保存在一个成员中,以便在有人调用Run
方法时可以调用它。@MichaelGraczyk:l在Runner
中作为注入操作具有意义。顺便说一句,这实际上不是好的OOP,因为您需要派生类调用基类函数。设计非常糟糕。它是一种常见的反模式(一种没有帮助或有害的模式).+1用于提及装饰器模式,这可能在他的实际案例中用于OP。这不起作用,因为只有int哈希表才是可实例化的。这就是您要寻找的吗?这不可能
class HashArrayInt : HashArray<int> {
public HashArrayInt(int n) : base (n,i => HashFunc(i,n)) {
}
private static int HashFunc(int i, int n) {
return (i%n);// n is a non static field, every hash table has its own size!
}
}
class HashFuncProvider {
private int n;
public HashFuncProvider(int n){
this.n = n;
}
public int HashFunc(int i) {
return (i%n);
}
}
class HashArrayInt : HashArray<int> {
public HashArrayInt(int n) : base (n, new HashFuncProvider(n).HashFunc) {
}
}