2017-01-03 64 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。 –

相關問題