2010-01-11 40 views
8

Tôi không biết nếu điều này là có thể, nhưng trong một số thử nghiệm đơn vị của tôi, tôi sẽ khởi tạo các đối tượng khác nhau với cùng một đối số. Tôi muốn để có thể lưu trữ những đối số trong một số thay đổi và chỉ khởi tạo các nhà xây dựng đối tượng đa tham số với biến mà nên thay vì thực hiện:C# nhiều đối số trong một để loại bỏ tham số đi qua

Thing thing1 = new Thing(arg1, arg2, arg3, arg4); 
Thing thing2 = new Thing(arg1, arg2, arg3, arg4); 
Thing thing3 = new Thing(arg1, arg2, arg3, arg4); 

tôi có thể làm như sau:

MagicalArgumentsContainer args = (arg1, arg2, arg3, arg4); 
Thing thing1 = new Thing(args); 
Thing thing2 = new Thing(args); 
Thing thing3 = new Thing(args); 

Có cách nào để làm điều này mà không ghi đè lên constructor của Thing để có một danh sách mà nó bằng tay phát nổ và plucks đối số ra khỏi? Có lẽ một số C# cú pháp đường?

+1

Không, bạn muốn sử dụng Ruby =). –

+2

Giải quyết đối số của Python là một phước lành! –

+1

Tôi _did_ tự nghĩ rằng, tôi đang sử dụng Ruby trong dự án này, tôi sẽ không phải hỏi câu hỏi này. –

Trả lời

13

Ý tôi là, có này:

Func<Thing> f =() => new Thing(arg1, arg2, arg3, arg4); 
Thing thing1 = f(); 
Thing thing2 = f(); 
Thing thing3 = f(); 
Thing thing4 = f(); 

Chỉ cần cẩn thận của closure semantics.

+1

vâng, đó giống như một ObjectFactory nhỏ trong dòng, nhưng hãy xem xét rằng nếu arg1-arg4 là kiểu tham chiếu, thì tất cả mọi thứ sẽ chia sẻ các đối tượng đó, nếu chúng là loại giá trị hoặc bạn không quan tâm nếu chúng được chia sẻ, thì đó có thể là dễ nhất –

+0

Trong trường hợp của tôi, arg1-4 là các chuỗi, vì vậy tất cả đều tốt. –

1

Ngoài ra còn có này, giả sử Thing1 của bạn là một đối tượng tầm thường, và bạn chỉ cần một bản sao cạn:

Thing thing1 = new Thing(arg1, arg2, arg3, arg4); 
Thing thing2 = (Thing)thing1.MemberwiseClone(); 
0

Bạn cũng có thể sử dụng một mảng các đối tượng và một vòng lặp for nếu bạn cần phải làm điều này nhiều lần.

1

Bạn có thể viết lại GimmieAThing vào một cái gì đó như GimmieAThing<T> bằng cách sử dụng một chút generics?

public class MagicalArgumentsContainer 
    { 
      object[] _myParams; 

      public MagicalArgumentsContainer (params object[] myParams) 
      { 
      _myParams = myParams; 
      } 

      public Thing GimmieAThing() 
      { 
    return new Thing(_myParams[0], _myParams[1], _myParams[2], _myParams[3]); 
     } 
    } 
3

Vâng, tôi đoán bạn có thể sử dụng một container IoC, vì nhiều điều này cũng cung cấp một ObjectFactory, nghĩa là bạn nói với IoC làm thế nào để làm cho một trường hợp mới của loại T và sau đó bạn chỉ cần hỏi các IoC để cung cấp cho bạn một ví dụ của nó.

Tuy nhiên nếu bạn không muốn để có được một IoC, bạn có thể làm cho mình một lớp nhà máy ít tuy nhiên

public MagicFactory 
{ 
    T arg1, T2 arg2, T3 arg3,.., TN argN; 

    public MagicFactory(T1 a1,..., TN aN) 
    { 
     this.arg1=a1; 
     ... 
     this.argN = an; 
    } 

    public Thing GimmeDaThing() 
    { 
     return new Thing(this.arg1,...,this.argN); 
    } 
} 

ghi nhớ rằng nếu các đối số không phải là kiểu giá trị, sau đó tất cả các trường lại Thing sẽ có tham chiếu đến cùng một đối tượng, vì vậy, mặc dù bạn có thể hiện khác nhau của Mọi thứ, tất cả chúng sẽ trỏ đến cùng một arg1. Những gì bạn có thể làm gì để khắc phục điều đó là để thực sự mất trong một Func trong tham số, vì vậy bạn có thể thực sự tạo ra một hình mới:

public MagicFactory 
{ 
    Func<T1> arg1, ,.., Func<TN> argN; 

    public MagicFactory(Func<T1> a1,..., Func<TN> aN) 
    { 
     this.arg1=a1; 
     ... 
     this.argN = an; 
    } 

    public Thing GimmeDaThing() 
    { 
     return new Thing(this.arg1(),...,this.argN()); 
    } 
} 

và bạn sẽ gọi nó là như thế này:

var magicContainer = new MagicFactory(()=> new T1(...),...,()=>new T2(..); 


var thing1 = magicContainer.GimmeDaThing(); 
var thing1 = magicContainer.GimmeDaThing(); 
var thing1 = magicContainer.GimmeDaThing(); 
var thing1 = magicContainer.GimmeDaThing(); 

và bạn sẽ nhận được một ví dụ mới của Thing mỗi lần, mỗi đối tượng có các đối tượng sở hữu riêng của họ.

+1

public MagicFactory ? – gingerbreadboy

1

Tôi khuyên bạn nên xem xét mẫu Test Data Builder. Nó hoạt động thực sự tốt khi bạn có nhiều thông số bạn muốn thay đổi độc lập, tái sử dụng và như vậy.

Bạn có thể sử dụng properties + object initializers for 'flat' classes hoặc chuỗi phương pháp chất lỏng thay thế. Tôi đã chơi đùa với cả hai và từng có lợi thế của nó.

Lợi ích:

  • Bạn có thể chụp các biến/giá trị đã được sử dụng để xây dựng một đối tượng
  • Bạn có thể tái sử dụng một trường hợp xây dựng nếu các giá trị phải mất nhiều loại đơn giản và/hoặc không thay đổi (loại giá trị, chuỗi, v.v.)
  • Bạn có thể thay đổi từng tham số một cách độc lập mà không bị nhiễu /mã trùng lặp Kiểm tra đọc thực sự độc đáo như, thay vì phải nhớ ctor param là cái gì, bạn thấy tên.

Nếu bạn cần tạo các phiên bản mới của từng thông số, hãy xem câu trả lời của bangoker.

Dù sao, đây là một số mã:

public class ThingBuilder 
{ 
    // set up defaults so that we don't need to set them unless required 
    private string m_bongoName = "some name"; 
    private DateTime m_dateTime = new DateTime(2001, 1, 1); 
    private int m_anotherArg = 5; 
    private bool m_isThisIsGettingTedious = true; 

    public ThingBuilder BongoName(string bongoName) 
    { 
     m_bongoName = bongoName; 
     return this; 
    } 

    public ThingBuilder DateTime(DateTime dateTime) 
    { 
     m_dateTime = dateTime; 
     return this;  
    } 

    // etc. for properties 3...N 

    public Thing Build() 
    {  
     return new Thing(m_bongoName, m_dateTime, m_anotherArg, m_isThisGettingTedious); 
    } 
} 

sử dụng (một lần chẳng hạn):

// notice that the parameters are now explicitly named + readable! 
Thingy builtInstance = new ThingBuilder() 
          .BongoName("um bongo") 
          .DateTime(DateTime.Now) 
          .GettingTedious(true) 
          .Build(); 

Nhiều trường hợp:

var builder = new ThingBuilder() 
        .BongoName("um bongo") 
        .DateTime(DateTime.Now) 
        .GettingTedious(true); 

// let's make multiple objects 
Thing builtThing = builder.Build(); 
Thing anotherBuiltThing = builder.Build(); 
1

Sử dụng params khai trong phương pháp của bạn như sau:

public Thing(params string[] args) 
{ 
    foreach(string s in args) 
    { 
     ... 
    } 
} 

và nó sẽ cho phép bạn làm như sau:

result = Things(arg1) 
result = Things(arg1,arg2) 
result = Things(arg1,arg2,arg3) 
result = Things(arg1,arg2,arg3,arg4) 
Các vấn đề liên quan