简体   繁体   中英

Protected constructor for :where new() constraint

I wrote a class using Decoration Pattern to avoid inheritance issues. And I made Factory Method to enforce component to copy its instance. The code would be like this:

public interface IFoo
{
    int Bar { get; set; }
}

public class Foo : IFoo
{
    public int Bar { get; set; }

    public Foo() { }
}

public abstract class FooDecorator : IFoo
{
    protected IFoo _Foo;
    
    public int Bar
    {
        get
        {
            return _Foo.Bar;
        }
        set
        {
            _Foo.Bar = value;
        }
    }

    public static TOutput Create<TOutput, TInput>(TInput foo)
            where TOutput : FooDecorator, new()
            where TInput : IFoo, new()
    {
        var copy = new TInput
        {
            Bar = foo.Bar
        };
        return new TOutput { _Foo = copy };
        }
    }
}

public class FooDecoratorImpl : FooDecorator
{
    public FooDecoratorImpl() {} // This is necessary only for new() constraint. I'd like to hide it.

    public static FooDecoratorImpl Create<T>(T foo) where T : IFoo, new()
    {
        return Create<FooDecoratorImpl, T>(foo);
    }
}

Foo foo = new Foo() { Bar = 1 };

FooDecoratorImpl decorator = FooDecoratorImpl.Create(foo);
Console.WriteLine(decorator.Bar) // show "1"

FooDecoratorImpl unintended = new FooDecoratorImpl(); // I don't like to do this!

Since the default constructor is read only on the FooDecorator.Create(foo) method, I'd like its access modifier set to protected (I knew this doesn't work because FooDecorator isn't FooDecoratorImpl 's derived type, but the other way round.) to prevent unintended instantiation. But the constructor needs to be public. How can I restrict the constructor to be loaded on FooDecorator.Create(foo) only?

Use generic classes with regular constructors:

public abstract class FooDecorator<TSource> : IFoo
    where TSource : IFoo, new()
{
    protected IFoo _Foo;
    
    public int Bar
    {
        get
        {
            return _Foo.Bar;
        }
        set
        {
            _Foo.Bar = value;
        }
    }

    protected FooDecorator(TSource foo)
    {
        // TODO: null check foo
        var copy = new TSource
        {
            Bar = foo.Bar
        };

        _Foo = copy;
    }
}

public class FooDecoratorImpl<TSource> : FooDecorator<TSource>
    where TSource : IFoo, new()
{
    public FooDecoratorImpl(TSource foo)
        : base(foo)
    {
    }
}

Foo foo = new Foo() { Bar = 1 };

var decorator = new FooDecoratorImpl<Foo>(foo);
Console.WriteLine(decorator.Bar) // show "1"

// this won't compile
var unintended = new FooDecoratorImpl<Foo>(); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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