通过"这个"基础构造函数

时间:2017-08-27 08:11:28

标签: c#

有没有办法通过"这个"到基础构造函数?

abstract class Base<TSelf>
{
    public ICollection<TSelf> List;

    public Base(ICollection<TSelf> list, TSelf self)
    {
        List = list;
        List.Add(self);
    }
}

class Implementation : Base<Implementation>
{
    public Implementation() : base(new List<Implementation>(), this)
    {
    }
}

显然,Implementation的构造函数中存在编译错误,其中this传递给base

我也认为没有办法在list级别实例化Base

2 个答案:

答案 0 :(得分:7)

不,您不能在构造函数初始值设定项中使用this。您之后必须添加调用Add(this) - 但只要您转换为Base<TSelf>,就可以在TSelf构造函数中执行此操作。在转换为this之前,您需要先将object转换为TSelf,但出于相当复杂的原因,不幸的是,类型参数允许转换。

您可以在List<TSelf>构造函数中创建Base,但没有问题。以下示例代码显示了这两个:

abstract class Base<TSelf>
{
    // Let's make it a property rather than a public field...
    public ICollection<TSelf> List { get; }

    public Base()
    {
        List = new List<TSelf>();
        // This will obviously fail if you try to create a `Base<Foo>`
        // from a class that isn't a Foo
        TSelf selfThis = (TSelf) (object) this;
        List.Add(selfThis);
    }
}

class Implementation : Base<Implementation>
{
}

您可以向TSelf添加约束,以使投射失败不太可能,但并非不可能:

abstract class Base<TSelf> where TSelf : Base<TSelf>

这并不能阻止你写作

class Implementation : Base<Implementation> {}
class Evil : Base<Implementation> {}

然后,当您构建Evil的实例时,您正尝试向Evil添加List<Implementation>引用,但这些引用无法正常工作...并且转换无法停止你走得那么远。

答案 1 :(得分:0)

正如@Jon Skeet所说,您不能通过常规的旧构造函数调用传递this。但是,可以使用反射和FormatterServices类来实现。下面的示例代码使用工厂模式以提高可读性。


基类实现:

public abstract class Model<TSelf>
    where TSelf : Model<TSelf>
{
    public ICollection<TSelf> Items { get; }

    protected Model(TSelf self, ICollection<TSelf> items)
    {
        if ((self == null) || (items == null))
        {
            throw new ArgumentNullException();
        }

        if (self != this)
        {
            throw new ArgumentException();
        }

        Items = items;
        Items.Add(self);
    }
}

派生的类实现:

public sealed class ModelImplementation
    : Model<ModelImplementation>
{
    private ModelImplementation(ModelImplementation self)
        : base(self, new List<ModelImplementation>()) { }
}

此技术的主要内容是ModelFactory类,该类接受一个未初始化的对象并手动对其调用适当的构造函数。可以通过修改GetConstructorInvoke调用来实现对其他构造函数参数的支持。

您应该致电ModelFactory.Create<ModelImplementation>()以获得新的ModelImplementation来代替new关键字。

工厂类实现:

public static class ModelFactory
{
    public static Model<TSelf> Create<TSelf>()
        where TSelf : Model<TSelf>
    {
        var result = FormatterServices
            .GetUninitializedObject(typeof(TSelf));

        result.GetType()
            .GetConstructor(
                BindingFlags.Instance | BindingFlags.NonPublic,
                null,
                new[] { typeof(TSelf) },
                null)
            .Invoke(
                result,
                new[] { result });

        return (TSelf)result;
    }
}