2011-02-08 36 views
24

Khi bạn sử dụng lớp System.Random, bạn phải tạo một phiên bản của nó. Tại sao nó không phải là static? Bởi vì nếu tôi muốn có một số ngẫu nhiên từ 0 đến 9, tôi có thể sử dụng phương pháp tĩnh , System.Random.Next(int, int):Tại sao lớp System.Random không tĩnh?

int ourRandomNumber = Random.Next(0,9); 

Vậy tại sao không phải là lớp chỉ static?

Trả lời

31

Bạn sẽ không thể sử dụng các hạt giống khác nếu nó là tĩnh - trường hợp ngẫu nhiên theo dõi trạng thái đó. Theo mặc định, Random sử dụng thời gian hiện tại làm hạt giống, nhưng sử dụng lại một hạt giống cụ thể (ví dụ: new Random(42)) cho phép bạn lặp lại chính xác chuỗi số ngẫu nhiên - chúng sẽ luôn giống nhau cho cùng một hạt giống. Khía cạnh này rất quan trọng trong một số ứng dụng. Ví dụ: Minecraft.

+1

Và trong một số ứng dụng có thể lặp lại là không cần thiết. Tôi có thể nghĩ về những tình huống mà bạn muốn gieo hạt theo cách thủ công, nhưng tôi chưa bao giờ cá nhân cần thiết để đặt một cách rõ ràng. – Davy8

+1

@ Davy8 - điều đó rất đúng - trong hầu như tất cả các ứng dụng của tôi, tôi cũng không cần một hạt giống, nhưng 'Random' vẫn bao gồm chức năng đó. – BrokenGlass

+0

Tôi có một chương trình chó đua, di chuyển ngẫu nhiên và một sẽ thắng. Là giải pháp để làm cho cùng một hạt giống ?? –

17

Random không an toàn chỉ. Bạn nên có một phiên bản Random cho mỗi luồng, nhưng bạn không nên sử dụng một phiên bản từ nhiều luồng cùng một lúc. Vì vậy, bạn không thể chỉ có một thể hiện của Random trong một biến tĩnh và sử dụng nó từ phương thức tĩnh.

Ngoài ra, làm cho nó tĩnh sẽ loại bỏ cơ hội để cung cấp cho một hạt giống cụ thể, như đã đề cập bởi BrokenGlass.

Tất nhiên, sẽ không quá khó để tạo các phương pháp tĩnh đảm bảo an toàn luồng khi bạn không cần để chỉ định hạt giống, nhưng vẫn để phương pháp thể hiện khi bạn muốn sử dụng một ví dụ cụ thể. Cá nhân tôi tìm thấy nó thích hợp để điều trị "một nguồn số ngẫu nhiên" như là một phụ thuộc để được tiêm khi thích hợp.

Tôi có một số article which covers some of this và bạn có thể thấy nó hữu ích.

+1

+1 cho an toàn luồng. Tôi đôi khi nhầm lẫn đưa ra giả định rằng các lớp dựng sẵn là an toàn chỉ trừ khi được đánh dấu khác khi chúng thực sự không an toàn chỉ trừ khi chúng được cho là như vậy. – Davy8

+1

Bài viết của bạn rất hay, cảm ơn bạn –

4

Đôi khi bạn muốn "một điều gì đó ngẫu nhiên" và bạn không quan tâm đến việc giá trị ngẫu nhiên đó đến như thế nào. Có một phương pháp tĩnh để có thể làm việc.

Tuy nhiên, đôi khi bạn muốn có thể lặp lại có cùng chuỗi ngẫu nhiên. Đối với điều đó, bạn sử dụng quá tải của hàm tạo có giá trị hạt giống và trong trường hợp đó, bạn không muốn bất kỳ mã nào khác sử dụng số ngẫu nhiên để tiêu thụ một trong các số từ số chuỗi của bạn. Trong trường hợp đó, bạn chắc chắn cần một phiên bản của lớp

2

Có chuỗi lặp lại 'ngẫu nhiên' hữu ích trong các trường hợp thử nghiệm.

Ví dụ: bạn có thể sử dụng nó trong thử nghiệm công cụ trò chơi để đảm bảo rằng AI đang chọn đúng mục tiêu hoặc đường dẫn - ngay cả khi nó có đánh giá đường dẫn ngẫu nhiên.

Đây là một ví dụ rất đơn giản. Không có vấn đề bao nhiêu lần bạn chạy thử nghiệm này, nó sẽ luôn luôn chọn cùng một ba thẻ khi đưa ra cùng một cơ sở số ngẫu nhiên máy phát điện. Điều này có thể hữu ích để đảm bảo rằng trình tạo số ngẫu nhiên đang được sử dụng là trình cung cấp được cung cấp. Và, vì một lý do nào đó nếu một bộ tạo số ngẫu nhiên mới được giới thiệu mà không làm thay đổi phép thử, thì phép thử sẽ thất bại.

[TestMethod] 
public void TestRandomPicking() 
{ 
    Random random = new Random(1); 
    Deck deck = new Deck(random); 


    Assert.AreEqual(3, deck.PickCard().Value); 
    Assert.AreEqual(1, deck.PickCard().Value); 
    Assert.AreEqual(5, deck.PickCard().Value); 

} 

public class Deck 
{ 
    public Deck() 
    { 
     _randomizer = new Random(); 
    } 

    public Deck(Random randomizer) 
    { 
     _randomizer = randomizer; 
    } 

    Random _randomizer; 

    private List<Card> _cards = new List<Card> 
            { 
             new Card {Value = 1}, 
             new Card {Value = 2}, 
             new Card {Value = 3}, 
             new Card {Value = 4}, 
             new Card {Value = 5}, 
             new Card {Value = 6}, 
             new Card {Value = 7}, 
             new Card {Value = 8}, 
             new Card {Value = 9}, 
             new Card {Value = 10} 
            }; 

    private List<Card> Cards { get { return _cards; } } 

    public Card PickCard() 
    { 
     return Cards[_randomizer.Next(0, Cards.Count - 1)]; 
    } 
} 

public class Card 
{ 
    public int Value { get; set; } 
} 
1

Thông thường khi một người được gỡ một chương trình, hành vi không thích hợp tại một bước có thể không có triệu chứng rõ ràng cho đến khi nhiều bước nữa đã thực hiện, theo thời gian mà nguyên nhân ban đầu có thể đã được che khuất. Trong những trường hợp như vậy, có thể rất hữu ích khi có thể khởi động lại từ đầu chương trình bị trục trặc trên ví dụ:bước 1.000.000 và có nó chạy 999.990 đầu tiên hoặc như vậy bước chính xác như nó đã làm lần đầu tiên và sau đó tạm dừng để cho các lập trình viên kiểm tra trạng thái của nó. Việc gỡ lỗi như vậy sẽ không thể thực hiện được nếu một chương trình tạo ra các số "ngẫu nhiên" thực sự, nhưng sẽ thay thế nếu nó sử dụng một trình tạo giả ngẫu nhiên có thể được tải lại vào lần chạy thứ hai với cùng một hạt giống như được sử dụng trong lần chạy đầu tiên.

Các vấn đề liên quan