2008-09-25 28 views
6

Bản trình diễn đơn giản dưới đây ghi lại những gì tôi đang cố gắng thực hiện. Trong chương trình thực, tôi phải sử dụng khối khởi tạo đối tượng vì nó đang đọc một danh sách trong một biểu thức chọn LINQ to SQl, và có một giá trị mà tôi muốn đọc ra khỏi cơ sở dữ liệu và lưu trữ trên đối tượng, nhưng đối tượng không có một thuộc tính đơn giản mà tôi có thể đặt cho giá trị đó. Thay vào đó nó có một kho dữ liệu XML.Có cách nào để sử dụng phương pháp mở rộng trong khối khởi tạo đối tượng trong C#

Có vẻ như tôi không thể gọi phương thức mở rộng trong khối trình khởi tạo đối tượng và tôi không thể đính kèm thuộc tính bằng phương thức tiện ích.

Vì vậy, tôi không may mắn với cách tiếp cận này? Cách thay thế duy nhất có vẻ là thuyết phục chủ sở hữu của lớp cơ sở sửa đổi nó cho kịch bản này.

Tôi có một giải pháp hiện có nơi tôi phân lớp BaseDataObject, nhưng điều này cũng có vấn đề không hiển thị trong ví dụ đơn giản này. Các đối tượng được duy trì và phục hồi như BaseDataObject - các phôi và các phép thử sẽ trở nên phức tạp.

public class BaseDataObject 
{ 

// internal data store 
private Dictionary<string, object> attachedData 
              = new Dictionary<string, object>(); 

public void SetData(string key, object value) 
{ 
    attachedData[key] = value; 
} 

public object GetData(string key) 
{ 
    return attachedData[key]; 
} 

public int SomeValue { get; set; } 
public int SomeOtherValue { get; set; } 

} 

public static class Extensions 
{ 
    public static void SetBarValue(this BaseDataObject dataObject, 
             int   barValue) 
    { 
     /// Cannot attach a property to BaseDataObject? 
     dataObject.SetData("bar", barValue); 
    } 
} 

public class TestDemo 
{ 

public void CreateTest() 
{ 
    // this works 
    BaseDataObject test1 = new BaseDataObject 
     { SomeValue = 3, SomeOtherValue = 4 }; 

    // this does not work - it does not compile 
    // cannot use extension method in the initialiser block 
    // cannot make an exension property 
    BaseDataObject test2 = new BaseDataObject 
    { SomeValue = 3, SomeOtherValue = 4, SetBarValue(5) }; 
} 
} 

Một trong những câu trả lời (từ mattlant) gợi ý sử dụng phương pháp mở rộng kiểu giao diện thông thạo. ví dụ:

// fluent interface style 
    public static BaseDataObject SetBarValueWithReturn(
this BaseDataObject dataObject, int barValue) 
    { 
     dataObject.SetData("bar", barValue); 
     return dataObject; 
    } 

     // this works 
     BaseDataObject test3 = (new BaseDataObject 
{ SomeValue = 3, SomeOtherValue = 4 }).SetBarValueWithReturn(5); 

Nhưng điều này có hoạt động trong truy vấn LINQ không?

+0

Mục đích là để trừu tượng phương thức Đặt ra khỏi BaseDataObject? Tôi đặc biệt khuyên bạn chỉ nên sử dụng phân lớp với Thuộc tính Get/Set .. – Tigraine

Trả lời

3

Thậm chí tốt hơn:

public static T SetBarValue<T>(this T dataObject, int barValue) 
     where T : BaseDataObject 
    { 
     dataObject.SetData("bar", barValue); 
     return dataObject; 
    } 

và bạn có thể sử dụng phương pháp mở rộng này với nhiều loại nguồn gốc của BaseDataObject với các phương pháp chuỗi mà không phôi và duy trì các loại thực khi suy ra thành một lĩnh vực var hoặc loại vô danh.

4

Trình khởi tạo đối tượng chỉ là cú pháp cú pháp yêu cầu trình biên dịch thông minh và khi triển khai hiện tại, bạn không thể gọi các phương thức trong trình khởi tạo.

var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 }; 

sẽ nhận được biên dịch để một cái gì đó như thế này:

BaseDataObject tempObject = new BaseDataObject(); 
tempObject.SomeValue = 3; 
tempObject.SomeOtherValue = 4; 
BaseDataObject x = tempObject; 

Sự khác biệt là không thể có bất kỳ vấn đề đồng bộ hóa. Biến x get được gán cho BaseDataObject được gán đầy đủ cùng một lúc, bạn không thể gây rối với đối tượng trong khi khởi tạo nó.

Bạn chỉ có thể gọi phương thức mở rộng sau khi tạo đối tượng:

var x = new BaseDataObject { SomeValue = 3, SomeOtherValue = 4 }; 
x.SetBarValue() 

Bạn có thể thay đổi SetBarValue là một tài sản với get/set có thể được gán trong quá trình khởi:

public int BarValue 
{ 
    set 
    { 
     //Value should be ignored 
    } 
} 

Hoặc , bạn có thể phân lớp/sử dụng mẫu mặt tiền để thêm phương thức vào đối tượng của mình:

public class DataObjectWithBarValue : BaseDataObject 
{ 
    public void BarValue 
    { 
     set 
     { 
      SetData("bar", value); 
     } 
     get 
     { 
      (int) GetData("bar"); 
     } 
    } 
} 
4

Không, nhưng bạn có thể làm điều này ....:

BaseDataObject test2 = (new BaseDataObject { SomeValue = 3, SomeOtherValue = 4}).SetBarValue(5); 

ANd có tiện ích mở rộng của bạn trả về đối tượng như LINQ.

EDIT: Đây là một suy nghĩ tốt cho đến khi tôi đọc lại và thấy rằng lớp cơ sở đã được phát triển bởi một người thứ ba: aka bạn không có mã. Những người khác ở đây đã đăng một giải pháp đúng.

+0

Phải rất tốt để có điểm đại diện cao để chỉ cần đi và xóa câu trả lời sai của bạn thay vì sở hữu sai lầm của bạn:/(Bạn biết bạn là ai ;)) – mattlant

+0

Nó vẫn hoạt động. Các nhà cung cấp LINQ chỉ quan tâm đến một phần của truy vấn Chọn nơi các thành viên được ánh xạ được tham chiếu. –

+0

Tôi đã xóa của tôi vì tôi là bản sao của bạn. –

0

Mở rộng lớp học có khả năng không? Sau đó, bạn có thể dễ dàng thêm thuộc tính bạn cần.

Nếu không được, bạn có thể tạo một lớp mới có tính chất tương tự mà chỉ đơn giản gọi trở lại một trường hợp riêng của lớp bạn đang quan tâm.

1
static T WithBarValue<T>(this T dataObject, int barValue) 
     where T : BaseDataObject 
{ dataObject.SetData("bar", barValue);  
    return dataObject; 
} 

var x = new BaseDataObject{SomeValue=3, OtherValue=4}.WithBarValue(5); 
0

Phải, đã học được từ những người trả lời, ngắn trả lời cho "Có cách nào để sử dụng một phương pháp mở rộng trong một khối khởi tạo đối tượng trong C#?" là "số"

Cách mà tôi cuối cùng đã giải quyết được vấn đề mà tôi phải đối mặt (tương tự, nhưng phức tạp hơn rằng vấn đề đồ chơi mà tôi đặt ra ở đây) là một phương pháp lai, như sau:

tôi đã tạo một lớp con, ví dụ

public class SubClassedDataObject : BaseDataObject 
{ 
    public int Bar 
    { 
     get { return (int)GetData("bar"); } 
     set { SetData("bar", value); } 
    } 
} 

nào hoạt động tốt trong LINQ, khối khởi động trông như

SubClassedDataObject testSub = new SubClassedDataObject 
    { SomeValue = 3, SomeOtherValue = 4, Bar = 5 }; 

Nhưng lý do mà tôi không thích phương pháp này ở nơi đầu tiên là những đối tượng được đưa vào XML và đi trở lại như BaseDataObject, và đúc lại sẽ là một sự khó chịu, một bản sao dữ liệu không cần thiết, và sẽ đặt hai bản sao của cùng một đối tượng trong vở kịch.

Trong phần còn lại của mã này, tôi bỏ qua các lớp con và phương pháp khuyến nông sử dụng:

public static void SetBar(this BaseDataObject dataObject, int barValue) 
    { 
     dataObject.SetData("bar", barValue); 
    } 
    public static int GetBar(this BaseDataObject dataObject) 
    { 
     return (int)dataObject.GetData("bar"); 
    } 

Và nó hoạt động độc đáo.

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