2017-01-03 66 views
1

是否可以将对象创建限制为特定类的方法?如何将对象创建限制到特定类的方法?

对于为例:我有一个类事务,我想限制它创建对象,以从AbstractService或IService继承任何类的方法:

允许的情景:

public class ServiceA : AbstractService (or IService) 
{ 
    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 
    } 
} 

有一个访问修饰符或其他我可以安装该场景的东西?

+1

如果'ServiceA'与'Transaction'在同一个程序集中,但是在一个单独的程序集中,而不是'ServiceB',那么你可以为'Transaction'' internal'构造函数。否则,您可以将其设置为'private'并使用反射来创建它的一个实例,并禁止其他类通过抛出异常来创建实例。我认为这是你能做的最好的事情。 –

+2

排序回答:没有。 – Jamiec

+1

想不到应该如何实现这个优雅的方式。一个肮脏的黑客可能确实是检查'Transaction'的构造函数中的'StackFrame'。但实际上我认为你在这里有一个错误的设计决定,但我不能断定,如果不知道你正在努力实现什么。为什么你想这样做?如果'ServiceA.MethodA()'会调用'ServiceB.MethodA'然后创建'Transaction',它会是合法的吗?或者只有来自'ServiceA'的“直接”呼叫?不管“直接”意味着编译器优化之后的意思。 –

回答

2

有一个访问修饰符或其他的东西,我可以安装该场景?

是有别的,可以“安装”那情景,但它是一个大量的工作,并为抽象的,在我看来,很少奖励。这需要返回事务的接口,而不是具体的类型。 (我很肯定这是有效的,但我没有编译它)。

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() 
     { 
     } 
    } 
} 

作为一个侧面说明,有人在技术上可以传递,所以这将是最好做方法参数的其他检查(不过,这将是一个运行时的问题,而不是一个编译时间问题) 。

如果你想编译时检查,我认为你可以做...

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(); 
    } 
    // .... 

若第二个工作

+1

至少调用工厂方法'CreateTransaction',否则它看起来像你正在创建一个服务('var transaction = myServiceInstance.Create()'看起来很奇怪) – Jamiec

+0

我想这取决于它是否被用作ExtensionMethod或不。我同意。 –

2

简短的答案是否定的,没有访问修饰符,它说“这个对象只能从实现特定接口的类构造”。

您可以绕过此限制进行编码,但它远离清洁/万无一失。

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

这应该是显而易见的,以上是可以绕过的。我怀疑你有一个XY Problem和你认为这是解决它的方法。

+3

绝对是一个XY问题。 –

+0

它的解决方案的问题是:想象一下,类控制器,如果我在它的任何方法内创建一个服务,并将创建的服务传递给同一个方法内的一个事务,我可以。但是我希望这也是被禁止的,因为事务只能在特定服务的方法中被创建(这受到继承类,接口或其他方式的限制)。 –

+0

@ErikPhilips我同意,有时它很有帮助,以显示您的代码需要多么糟糕才能解决您认为的问题! – Jamiec

2

也许我误解你想要做什么不太清楚,但看起来这应该做的伎俩:

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

如果你希望其他人能够使用Transaction,你需要把它实现一些公共接口或和poorly从另一个公共类中放弃它,但现在可以确保没有其他人可以创建一个Transaction对象。

+0

我喜欢这个解决方案。 – Jamiec

+0

我不允许从接口派生的对象创建事务。 –

+0

“从接口派生”是什么意思?如果AbstractService声明为实现IService接口,那么可以有效地得到他想要的,因为每个子服务都必须实现IService。他也可以将IService声明为内部的,这会阻止任何外部用户实现他们自己的IService。 –

相关问题