Vinicius Ottoni
Vinicius Ottoni

Reputation: 4677

How to limit object creation to methods of specific class?

Is it possible to limit object creation to methods of specific class?

For exemple: I have a class Transaction, and I would like to limit it object creation to methods of any class that inherits from AbstractService or IService:

Allowed Scenario:

public class ServiceA : AbstractService (or IService)
{
    public void MethodA() 
    {
        var transaction = new Transaction();
    }

    public void MethodB() 
    {
        var transaction = new Transaction();
    }
}

Prohibited Scenario:

public class ServiceB
{
    public void MethodA() 
    {
        var transaction = new Transaction(); // cannot create
    }

    public void MethodB() 
    {
        var transaction = new Transaction(); // cannot create
    }
}

There is a access modifier or something else that I can mount that scenarios?

Upvotes: 3

Views: 651

Answers (3)

Erik Philips
Erik Philips

Reputation: 54628

There is a access modifier or something else that I can mount that scenarios?

Yes there is something else that can "mount" that scenario, but it's a lot of work and abstraction for, in my opinion, very little reward. This requires returning an interface of the Transaction, not a concrete type. (I'm pretty sure this works, I haven't compiled it however).

public abstract class AbstractService 
{
}

public interface IService
{
}

public interface ITransaction
{
}


public static class TransactionFactory 
{
    // created them as extensions, but you could remove *this*
    public static ITransaction CreateTransaction(this AbstractService instance)
    {
        return new Transaction ();
    }

    public static ITransaction CreateTransaction(this IService instance)
    {
        return new Transaction ();
    }

    private class Transaction : ITransaction
    {
        public Transaction ()
        {
        }
    }
}

As a side note, someone technically could pass in null, so it would be best to do additional checking of the method parameters (however, that would be a runtime issue instead of a compile time issue).

If you wanted compile time checking I think you could do...

public interface ITransactionFactory { }

public abstract class AbstractService : ITransactionFactory { }

public interface IService  : ITransactionFactory { }

public static class TransactionFactory<T>
  where T : ITransactionFactory
{
  public static ITransaction CreateTransaction(this T instance)
    {
        return new Transaction ();
    }
    // ....

Not quite sure if the second one works

Upvotes: 2

Emperor Eto
Emperor Eto

Reputation: 3520

Maybe I'm misunderstanding what you're trying to do, but it seems like this should do the trick:

public abstract class AbstractService : IService
{
    protected class Transaction
    {

    }
}

public class ServiceA : AbstractService
{
    public void MethodA()
    {
        var transaction = new Transaction();
    }

    public void MethodB()
    {
        var transaction = new Transaction();
    }
}

public class ServiceB
{
    public void MethodA()
    {
        var transaction = new Transaction(); // cannot create
    }

    public void MethodB()
    {
        var transaction = new Transaction(); // cannot create
    }
}

internal interface IService
{
}

If you want anyone else to be able to use the Transaction, you'll need to have it implement some public interface or inherit it from another public class, but you can now ensure that no one else can create a Transaction object.

Upvotes: 2

Jamiec
Jamiec

Reputation: 136114

The short answer is no, there is no access modifier which says "This object can only be constructed from a class which implements a specific interface".

You could code your way round this limitation, but its far from clean/foolproof.

public class Transaction
{
    private Transaction(){} // private important!

    public static Transaction Create(object creator)
    {
        if(creator is IService)
            return new Transaction();

        throw new InvalidOperationException();
    }
}

public class ServiceA : IService
{
    public void MethodA() 
    {
        var transaction = Transaction.Create(this);  // works
    }
}


public class ServiceB
{
    public void MethodA() 
    {
        var transaction = Transaction.Create(this);  // fails
    }
}

It should be obvious how easily circumventable the above is. I suspect you have an XY Problem and you think this was the way to solve it.

Upvotes: 2

Related Questions