为什么我不能在抽象 C# 类上创建抽象构造函数?

发布于 2024-07-13 00:38:39 字数 872 浏览 7 评论 0 原文

我正在创建一个抽象类。 我希望我的每个派生类都被迫实现构造函数的特定签名。 因此,如果我想强迫他们实现一种方法,我做了我会做的事情,我做了一个抽象的方法。

public abstract class A
{
    abstract A(int a, int b);
}

但是我收到一条消息,说抽象修饰符对此项目无效。 我的目标是强制执行一些这样的代码。

public class B : A
{
    public B(int a, int b) : base(a, b)
    {
        //Some other awesome code.
    }
}

这是所有 C# .NET 代码。 谁能帮我吗?

更新 1

我想添加一些内容。 我最终得到的是这个。

private A() { }

protected A(int a, int b)
{
    //Code
}

这就是一些人所说的,默认是私有的,并且该类需要实现一个构造函数。 然而,这并不强制使用签名 A(int a, int b) 的构造函数。

public abstract class A
{
    protected abstract A(int a, int b)
    {


    }
}

更新 2

我应该清楚,为了解决这个问题,我将默认构造函数设为私有,并将其他构造函数设为受保护。 我并不是真的在寻找一种让我的代码工作的方法。 我照顾好了。 我想了解为什么 C# 不允许你这样做。

I am creating an abstract class. I want each of my derived classes to be forced to implement a specific signature of constructor. As such, I did what I would have done has I wanted to force them to implement a method, I made an abstract one.

public abstract class A
{
    abstract A(int a, int b);
}

However I get a message saying the abstract modifier is invalid on this item. My goal was to force some code like this.

public class B : A
{
    public B(int a, int b) : base(a, b)
    {
        //Some other awesome code.
    }
}

This is all C# .NET code. Can anyone help me out?

Update 1

I wanted to add some things. What I ended up with was this.

private A() { }

protected A(int a, int b)
{
    //Code
}

That does what some folks are saying, default is private, and the class needs to implement a constructor. However that doesn't FORCE a constructor with the signature A(int a, int b).

public abstract class A
{
    protected abstract A(int a, int b)
    {


    }
}

Update 2

I should be clear, to work around this I made my default constructor private, and my other constructor protected. I am not really looking for a way to make my code work. I took care of that. I am looking to understand why C# does not let you do this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

会傲 2024-07-20 00:38:39

您不能拥有抽象构造函数,因为抽象意味着您必须在任何非抽象子类中重写它,并且不能重写构造函数。

如果您考虑一下,这是有道理的,因为您总是调用子类的构造函数(使用 new 运算符)而不是基类。

一般来说,C# 中强制执行特定构造函数签名的唯一方法是使用 new() 泛型约束,该约束强制类型参数存在无参数构造函数。

You cannot have an abstract constructor because abstract means you must override it in any non-abstract child class and you cannot override a constructor.

If you think about it, this makes sense, since you always call the constructor of the child class (with the new operator) and never the base class.

Generally speaking, the only way in C# to enforce a specific constructor signature is by using the new() generic constraint, which enforces the existence of a parameterless constructor for the type parameter.

后知后觉 2024-07-20 00:38:39

将 A 类中的构造函数更改为

protected A(int a, int b)
{
    // Some initialisation code here
}

然后您的子类将必须使用它,因为没有默认构造函数。

但是,他们仍然可以更改构造函数的实际签名。 据我所知,没有办法强制子类为其构造函数使用特定的签名。 我很确定构造函数不能是抽象的。

您到底需要这个做什么? 我们也许可以建议解决此问题的方法。

Change that constructor in class A to

protected A(int a, int b)
{
    // Some initialisation code here
}

Then your subclasses will have to use it, as there is no default constructor.

They can, however, still change the actual signature of the constructor. There is no way of forcing a subclass to use a specific signature for its constructor as far as I know. I'm pretty sure constructors can't be abstract.

What exactly do you need this for? We might be able to suggest a work around for this.

不醒的梦 2024-07-20 00:38:39

尽管您无法重写构造函数,因此无法定义抽象构造函数,但您可以在抽象基类中放置抽象工厂方法。 所有派生类都需要重写它。

public abstract class A 
{ 
    abstract A MakeAInstance(int a, int b); 
} 

public class B : A 
{ 
    // Must implement:
    override A MakeAInstance(int a, int b) {
        // Awesome way to create a B instance goes here
    }
} 

Although you can't override constructors, and therefore can't define an abstract constructor, you can place an abstract factory method in your abstract base class. All the derived classes would need to override that.

public abstract class A 
{ 
    abstract A MakeAInstance(int a, int b); 
} 

public class B : A 
{ 
    // Must implement:
    override A MakeAInstance(int a, int b) {
        // Awesome way to create a B instance goes here
    }
} 
櫻之舞 2024-07-20 00:38:39

多个原因:

1)构造函数不是继承的,因此您无法覆盖它们。

2)构造函数是静态成员函数,因为它不需要调用特定的实例。 Abstract 意味着“虚拟”,这意味着实现可以根据特定实例的子类化方式而变化,这与“static”关键字的含义相反。

Multiple reasons:

1) Constructors are not inherited thus you cannot override them.

2) The constructor is a static member function since it dont need a specific instance to be called. Abstract implies "virtual" which means that the implementation can vary depending on how a specific instance is subclassed, which is the opposite of the intention of the meaning of the "static" keyword.

清音悠歌 2024-07-20 00:38:39

您不能强制执行构造函数签名,因为每个派生类可以(必须!)定义自己的构造函数,并且它们可以采用它们喜欢的任何参数。

如果需要将给定的一组变量传递给派生类的对象,请定义一个需要由派生类实现的抽象方法。 如果类没有实现抽象方法,您将收到编译器错误。

You cannot enforce constructor signature, as each derived class may (must!) define its own constructor(s), and they may take any parameters they like.

If you need to pass a given set of variables to an object of a derived class, define an abstract method which needs to be implemented by derived classes. If the classes do not implement the abstract method, you will get a compiler error.

旧夏天 2024-07-20 00:38:39

希望这能帮助像我这样的新手
我正在寻找一个带有接受参数的 ctor 的“正常”公共类,然后我需要将其设为子类,所以我需要一个空的 ctor。

我以前不知道这一点:如果你创建一个受保护的 ctor,那么子类会看到它,但程序的其余部分看不到它(我想我的困惑是因为在 asp.net 中,我看到继承自的 aspx 页面中的所有受保护的CS...)

hope this will help someone newb as i am
i was looking to make a "normal" public class with a ctor that takes argument and then i needed to make it a child class so i needed an empty ctor for it.

i didnt know this before: if you make a protected ctor then the child class sees it but the rest of the program dont see it (i guess my confusion is since in asp.net i see all the protected in the aspx page which inherits from the cs...)

差↓一点笑了 2024-07-20 00:38:39

所有子类总是可以指定自己的构造函数,只要它们调用超类的构造函数 - 因此没有办法强制一个类具有特定的构造函数(至少,这是它在 Java 中的工作方式)。 您可以看到使用工厂模式会让您有所收获 - 您可以在接口中定义工厂方法 - 但您需要一个单独的工厂类,因为您的抽象基类不知道需要的对象的实际类创建的。

但是:也许添加您遇到的问题的更具体的示例可能会提示其他/更好的响应。 您是否正在寻找一些通用实例化代码,或者您是否担心必须对抽象基类进行特定设置?

如果您只关心必须由抽象类完成的初始化,请创建一个方法来执行此操作,并记录该方法的用法。

All subclasses always can specify their own constructor as long as they call a constructor of the superclass - so there is no way of forcing the a class to have a specific constructor (At least, that is the way it works in Java). You could see of using a factory pattern will get you somewhere - you could define a factory method in an interface - but you'll need a separate factory class as your abstract base class does not know the actual class of the object that needs to be created.

However: maybe adding a more concrete example of the issue you are having might prompt other/better responses. Are you looking for some generic instantiation code, or are you concerned specific settings on the abstract base class have to be done?

If you are just concerned about initialization that has to be done by the abstract class, create a method to do so, and document the usage of that method.

像你 2024-07-20 00:38:39

不确定这是否有帮助 - 但我觉得这将是您问题的解决方案:

public class A
{
  public A(int a, int b)
  {
    DoSomething(int a, int b);
  }

  virtual public void DoSomething(int a, int b)
  {

  }
}

public class B : A
{
  override public void DoSomething(int a, int b)
  {
    //class specific stuff
  }
}

结果是您可以在任何派生类中以正确的行为调用具有所需参数的构造函数。

not sure if this helps - but i feel this would be a solution to your problem:

public class A
{
  public A(int a, int b)
  {
    DoSomething(int a, int b);
  }

  virtual public void DoSomething(int a, int b)
  {

  }
}

public class B : A
{
  override public void DoSomething(int a, int b)
  {
    //class specific stuff
  }
}

with the result that you can call a constructor with the required arguments in any derived class with the correct behaviour.

君勿笑 2024-07-20 00:38:39

C# 11 和 .NET 7 引入了

public interface IBase<TDerived> where TDerived : Base<TDerived>, IBase<TDerived>
{
    public static abstract TDerived CreateInstance(int a, int b);
}

public abstract class Base<TDerived> where TDerived : Base<TDerived>, IBase<TDerived>
{
    protected Base(int a, int b) { }
}

然后,在其他一些程序集中

public class Derived : Base<Derived>, IBase<Derived>
{
    static Derived IBase<Derived>.CreateInstance(int a, int b)
    {
        return new(a, b);
    }

    public Derived(int a, int b) : base(a, b) { }
}

这个解决方案确实有点代码臭味,它有一个 private protected 基类构造函数和一个单独的接口,必须实施。 不幸的是,类中没有静态抽象/静态虚拟方法(还没有?),但尽管有这种味道,这个解决方案仍然有效。

我正在使用此模式从非托管数据创建托管类实例。 我有一个可扩展(非泛型)Base 类,并且可以随时添加新的Derived 类(甚至是从其他程序集),因此我无法确定地选择在编译时实例化正确的类,但我可以使用运行时数据来确定这一点。 我的 Base 类拥有一个静态 Dictionary>。 然后,在 Base 类构造函数中,我填充该字典(在第一次实例化 Derived 类时,新键将添加到字典中)。

protected Base(int a, int b) : base(a, b) // Base<TDerived> ctor, calls non-generic Base ctor
{
    // cache factory functions
    _ = instanceCreators.TryAdd(GetKey(a, b), TDerived.CreateInstance);
    // Func is covariant and accepts the more derived return type
    // GetKey maps the unmanaged data to a unique key
}

从那里,我的 Base 类可以返回任何 Derived 类的完整实例:

public static Base GetDerived(int a, int b) // in Base class
{
    return instanceCreators[GetKey(a, b)](a, b); // calls Derived class constructor
}

因为可以添加新的 Derived 类型,甚至可以从外部添加程序集,没有更优雅的解决方案来从 Base 类创建我需要的实例。 希望静态抽象方法也能扩展到抽象类,这样至少可以删除接口。 这个办法暂时有效。

编辑:不知何故,我忽略了private protected访问修饰符的引入,它比使用internal更适合这种荒谬的方法。

编辑2:进一步思考,一般情况下不需要非泛型Base类。 我只需要它来缓存实际生成 Derived 实例的 Func 。 删除中间的非通用 Base 类可以使一般情况实现更简单。

C# 11 and .NET 7 have introduced static virtual members in interfaces, which can be used (albeit in a contrived way) to enforce a factory method with a given signature.

public interface IBase<TDerived> where TDerived : Base<TDerived>, IBase<TDerived>
{
    public static abstract TDerived CreateInstance(int a, int b);
}

public abstract class Base<TDerived> where TDerived : Base<TDerived>, IBase<TDerived>
{
    protected Base(int a, int b) { }
}

And then, in some other assembly:

public class Derived : Base<Derived>, IBase<Derived>
{
    static Derived IBase<Derived>.CreateInstance(int a, int b)
    {
        return new(a, b);
    }

    public Derived(int a, int b) : base(a, b) { }
}

This solution is admittedly a bit code-smelly with an private protected base class constructor and a separate interface that must be implemented. Unfortunately, there are no static abstract/static virtual methods in classes (yet?), but despite the smell this solution is functional.

I am using this pattern to create managed class instances from unmanaged data. I have an extensible (non-generic) Base class and new Derived classes may be added at any time (even from other assemblies), so I can't deterministically select the right class to instantiate at compile-time, but I can use runtime data to determine this. My Base class holds a static Dictionary<int, Func<int, int, Base>>. Then in the Base<TDerived> class constructor, I populate that dictionary (new keys are added to the dictionary at the first instantiation of a Derived class).

protected Base(int a, int b) : base(a, b) // Base<TDerived> ctor, calls non-generic Base ctor
{
    // cache factory functions
    _ = instanceCreators.TryAdd(GetKey(a, b), TDerived.CreateInstance);
    // Func is covariant and accepts the more derived return type
    // GetKey maps the unmanaged data to a unique key
}

From there, my Base class can return full instances of any of the Derived classes:

public static Base GetDerived(int a, int b) // in Base class
{
    return instanceCreators[GetKey(a, b)](a, b); // calls Derived class constructor
}

Because new Derived types can be added, even from outside the assembly, there isn't a more elegant solution to creating the instances I need from the Base class. Hopefully static abstract methods will be extended to abstract classes as well so the interface can be removed, at least. This approach will work for the time being.

Edit: Somehow, I overlooked the introduction of the private protected access modifier, which is a much better fit for this absurd approach than using internal.

Edit 2: On further reflection, there's no need for the non-generic Base class in the general case. I just needed it for caching the Func that actually yields the Derived instances. Removing the intermediary, non-generic Base class makes the general case implementation simpler.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文