2010-04-29 34 views
10

có thể dễ dàng và động trang trí một đối tượng không? Ví dụ:Các đối tượng trang trí động trong C#

, cho phép nói rằng tôi có số List<PointF>. danh sách này thực sự là một âm mưu của hàm sin. Tôi muốn đi qua những điểm này và thêm một lá cờ cho mỗi PointF cho dù đó là một đỉnh hay không.

nhưng tôi không muốn tạo SpecialPointF mở rộng mới hoặc bất kỳ thứ gì, có thuộc tính boolean.

phán xét tôi tất cả các bạn muốn cho lười biếng, nhưng sự lười biếng là như thế nào ý tưởng tuyệt vời được sinh ra (còn ý tưởng xấu)

Edit: Tôi sẽ chấp nhận giải pháp đấm bốc cũng như bất kỳ hack thú vị bạn có thể đưa ra. không có gì thực sự ngăn tôi bắt nguồn. Tôi chỉ muốn biết nếu có một cách thú vị hơn.

+1

Tôi vừa cung cấp cho bạn +1 cho câu kết thúc. Không thực sự chắc chắn về một câu trả lời cho câu hỏi của bạn, mặc dù. –

Trả lời

4

Nếu có cách bạn có thể tính toán cho mỗi điểm, bạn không cần thêm cờ vào nó, bạn có thể sử dụng phương thức extension mà không phải kéo dài.

Giống như PointF.isPeak();

Nó hoạt động giống như:

public static class Extensions 
{ 
    public static bool isPeak (this PointF p) 
    { 
     do crazy math... 

     return result; 
    } 
} 

Và thì đấy, bạn phải tính toán của bạn trong lớp PointF của bạn.

Nhân tiện, lớp tĩnh công khai phải nằm trong phạm vi ngoài cùng, không thể lồng nhau.

+1

+1. Đề xuất tuyệt vời, mặc dù 'isPeak' không được đặt tên phù hợp với quy ước đặt tên .NET (ký tự đầu tiên phải được viết hoa) –

+0

Đó là một ý tưởng tuyệt vời. Tôi thích nó. –

+0

@Francisco: Phương pháp mở rộng là một ý tưởng tuyệt vời, nhưng trong trường hợp này làm thế nào một điểm sẽ biết nếu đỉnh của nó trong một chuỗi mà nó không chứa? Trừ khi điểm có chứa một con trỏ vào chuỗi đó là một phần của ... –

5

Không, không có cách nào để làm (cụ thể) những gì bạn đang yêu cầu.

Giả sử bạn đang sử dụng C# 3.0+, bạn có thể sử dụng các loại ẩn danh để thực hiện việc này, giả định rằng bạn không muốn để lộ thông tin bên ngoài chức năng của mình.

var decoratedList = sourceList.Select(pt => new 
        { 
         IsPeak = GetIsPeak(pt), 
         Point = pt 
        }).ToList(); 

Điều này sẽ cung cấp cho bạn đối tượng List<T> mới. Điều này có thể không giải quyết được vấn đề của bạn, vì bạn không thể mở rộng điều này bên ngoài một cuộc gọi chức năng duy nhất và bạn đang tạo một danh sách mới thay vì sửa đổi danh sách hiện tại, nhưng hy vọng điều này sẽ hữu ích.

+0

Đó là một ý tưởng hay. Tôi chưa sử dụng các loại ẩn danh, vì vậy tôi thậm chí không nghĩ về nó. chúng tôi khá thú vị khi sử dụng C# mới nhất, do đó, nó không phải là vấn đề. –

+0

@Oren: Chúng rất hay, nhưng cảnh báo lớn nhất là không thể phơi bày chúng bên ngoài chức năng của bạn. Nếu bạn cần làm điều đó, bạn sẽ phải tạo lớp wrapper đơn giản của riêng bạn với một chữ ký tương tự, sau đó chỉ cần nói 'new WrapperClass {...' thay vì chỉ 'new {...' –

2

Không thể thực hiện được.

gần nhất sẽ chỉ tạo ra một

var decorationData = new Dictionary <Object, bool> 

và sau đó lưu giá trị của bạn trong đó. Không cần phải mở rộng loại trực tiếp. Bạn thậm chí có thể sử dụng một phương pháp mở rộng để truy cập dữ liệu được lưu trữ mà sau đó sẽ trông giống như nó là một tài sản trực tiếp của đối tượng.

public static class PointFPeakExtensions 
{ 
    private static var decorationData = new Dictionary <PointF, bool> 

    public static bool IsPeak (this PointF point) 
    { 
     return decorationData[point]; 
    } 
    public static void SetPeak (this PointF point, bool isPeak) 
    { 
     decorationData[point] = isPeak; 
    } 
} 

Và thêm vào chỉnh sửa của bạn:

Bạn cũng có thể giải quyết việc này với một kiểu chung chung mà chỉ chứa các dữ liệu trang trí và kiểu tham chiếu (Trong cùng một cách như các loại Nullable được thực hiện trong các thư viện lớp). Tuy nhiên điều đó vẫn có nghĩa là bạn phải thay đổi chữ ký ở những nơi bạn sử dụng loại (có thể không phải là những gì bạn muốn làm khi tìm kiếm trang trí).

3

thể có thể làm điều này bằng cách sử dụng dynamic từ khóa mới và ExpandoObject xây dựng trong C# 4.0, nhưng tôi không có kinh nghiệm trực tiếp với nó được nêu ra. Theo tôi được biết đã được tạo ra để giải quyết vấn đề này chính xác một cách dễ dàng, vì vậy bạn có thể nói

dynamic something = new ExpandoObject(); 
something.Anything = "whatever you want"; 

tôi tin nó có thể mở rộng các loại hiện có động, nhưng nó có thể yêu cầu tạo một lớp con mới, trong đó sẽ đánh bại toàn bộ mục đích của bài tập.

Một giải pháp gần như giống hệt nhau có thể được tạo bằng cách sử dụng các phương pháp mở rộng. ExpandoObject được triển khai nội bộ dưới dạng Dictionary, nhưng nó thêm cú pháp gốc sang trọng.

class Program { 

    static void Main(string[] args) 
    { 
     PointF p = new PointF(0, 0); 

     p.SetFlag(true); 

     if (p.GetFlag()) 
     Console.WriteLine("win"); 
    } 

} 

public static class Extensions 
{ 
    private static Dictionary<PointF, bool> flags = new Dictionary<PointF, bool>(); 
    public static bool GetFlag(this PointF key) 
    { 
     return flags[key]; 
     //OR return flags.ContainsKey(key) ? flags[key] : false; 
    } 

    public static void SetFlag(this PointF key, bool val) 
    { 
     flags[key] = val; 
    } 
} 
+0

thay vì p.SetFlag bạn muốn gọi Extensions.SetFlag (p, true); ? –

+0

Không, các phương pháp mở rộng cho phép bạn thực hiện các cuộc gọi trông giống như "bản địa" như vậy. Nó tự động gọi 'Extensions.SetFlag (p, true)' cho bạn. –

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