简体   繁体   English

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

[英]Why can't I create an abstract constructor on an abstract C# class?

I am creating an abstract class. I want each of my derived classes to be forced to implement a specific signature of constructor.我正在创建一个抽象 class。我希望我的每个派生类都被迫实现构造函数的特定签名。 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.这是所有 C# .NET 代码。 Can anyone help me out?谁能帮我吗?

Update 1更新 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.这就是一些人所说的,默认是私有的,class 需要实现一个构造函数。 However that doesn't FORCE a constructor with the signature A(int a, int b).但是,这不会强制使用签名为 A(int a, int b) 的构造函数。

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


    }
}

Update 2更新 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.我想了解为什么 C# 不允许您这样做。

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. 如果你考虑一下,这是有道理的,因为你总是调用子类的构造函数(使用new运算符)而不是基类。

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. 一般来说,C#中强制执行特定构造函数签名的唯一方法是使用new()泛型约束,该约束强制存在type参数的无参数构造函数。

Change that constructor in class A to 将A类中的构造函数更改为

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. 我们或许可以建议解决这个问题。

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
    }
} 

Multiple reasons: 多种原因:

1) Constructors are not inherited thus you cannot override them. 1)构造函数不是继承的,因此您无法覆盖它们。

2) The constructor is a static member function since it dont need a specific instance to be called. 2)构造函数是一个静态成员函数,因为它不需要调用特定的实例。 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. Abstract暗示“虚拟”,这意味着实现可以根据特定实例的子类化方式而有所不同,这与“static”关键字含义的意图相反。

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. 如果类没有实现抽象方法,则会出现编译器错误。

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. 希望这会帮助某人newb,因为我正在寻找一个“正常”的公共课,其中一个ctor接受争论然后我需要让它成为一个儿童类,所以我需要一个空的ctor。

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...) 我以前不知道这个:如果你创建一个受保护的ctor然后子类看到它但程序的其余部分看不到它(我想我的困惑是因为在asp.net我看到aspx页面中的所有受保护继承自cs ...)

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. 结果是,您可以使用正确的行为在任何派生类中调用具有所需参数的构造函数。

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). 所有子类总是可以指定自己的构造函数,只要它们调用超类的构造函数 - 所以没有办法强制类具有特定的构造函数(至少,这是它在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. 如果您只关心必须由抽象类完成的初始化,请创建一个方法来执行此操作,并记录该方法的用法。

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. C# 11 和 .NET 7 在接口中引入了 static 虚拟成员,它们可用于(尽管是以人为的方式)强制执行具有给定签名的工厂方法。

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

public abstract class Base
{
    private protected Base(int a, int b) { }
}

public abstract class Base<TDerived> : Base where TDerived : Base<TDerived>, IBase<TDerived>
{
    protected Base(int a, int b) : base(a, 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, an intermediary base class, and a separate interface that must be implemented.诚然,这个解决方案有点代码味,它有一个private protected基 class 构造函数、一个中间基 class 和一个必须实现的单独interface Unfortunately, there are no static abstract / static virtual methods in class es (yet?), but despite the smell this solution is functional.不幸的是,在class es 中没有static abstract / static virtual methods(还没有?),但尽管有异味,这个解决方案仍然有效。

I am using this pattern to create managed class instances from unmanaged data.我正在使用此模式从非托管数据创建托管 class 实例。 I have an extensible 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.我有一个可扩展的Base class 并且可以随时添加新的Derived类(甚至来自其他程序集),因此我无法确定性地 select 正确的 class 在编译时实例化,但我可以使用运行时数据来确定这一点。 My Base class holds a static Dictionary<int, Func<int, int, Base>> .我的Base class 拥有一个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).然后在Base<TDerived> class 构造函数中,我填充该字典(在Derived类的第一次实例化时将新键添加到字典中)。

protected Base(int a, int b) : base(a, b) // Base<TDerived>
{
    _ = 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:从那里,我的Base class 可以返回任何Derived类的完整实例:

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 class es as well so the interface can be removed, at least.因为可以添加新的Derived类型,甚至可以从程序集外部添加,所以没有更优雅的解决方案来从Base class 创建我需要的实例。希望static abstract方法也将扩展为abstract class es,以便interface可以被删除,至少。 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 .编辑:不知何故,我忽略了private protected访问修饰符的引入,它比使用internal更适合这种荒谬的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM