2013-07-30 24 views
5

CTO của tôi (Giám đốc kỹ thuật) yêu cầu tôi tìm ra cách để viết một hàm duy nhất trong lớp cơ sở và truy cập tất cả các thuộc tính của lớp trẻ em. Dưới đây là những gì tôi đã đưa ra -Truy cập các thuộc tính lớp con thông qua hàm trong lớp cha

Base Class

class Assets 
{ 
    public Assets getPropertyVal(Assets asObj) 
    { 
     PropertyInfo[] propInfos = asObj.GetType().GetProperties(); 
     string strAttributeValue = "10"; 
     foreach (PropertyInfo propInfo in propInfos) 
     { 
      // Getting the value 
      var propValue = propInfo.GetValue(asObj, null); 

      // Setting the value 
      propInfo.SetValue(asObj, Convert.ChangeType(strAttributeValue, propInfo.PropertyType), null); 

     } 
     return asObj; 
    } 
} 

Child Lớp

class House : Assets 
{ 
    public int rooms{get; set;} 
} 

Program.cs nộp

class Program 
{ 
    static void Main(string[] args) 
    { 
     House hsObj = new House(); 
     hsObj.rooms = 5; 

     Assets asObj = hsObj.getPropertyVal(hsObj); 
     // Returns asObj as JSON 
    } 
} 

Bây giờ điều này hoạt động tốt, nhưng tôi đã chỉ tự hỏi nếu có một cách tốt hơn để làm điều này trong C#.

Lưu ý rằng chúng ta không biết những gì tính sẽ có mặt trong lớp trẻ, vì vậy đây sẽ phải được xác định tại thời gian chạy.

CẬP NHẬT: Làm cho nó rõ ràng, tôi chỉ tự hỏi nếu có một cách tốt hơn để truy cập vào các thuộc tính của lớp trẻ, một mà không sử dụng phản ánh. Điểm quan trọng cần lưu ý là chúng ta không biết các thuộc tính mà lớp con có thể có.

CẬP NHẬT # 2: Tôi đang làm việc với một sản phẩm có nhiều thực thể. Các thực thể này có các thuộc tính khác nhau. Tôi muốn có thể truy cập và làm việc với tất cả các thuộc tính này ở một nơi duy nhất. Chức năng này chính xác. Đó là một nơi duy nhất từ ​​nơi tôi có thể truy cập tất cả dữ liệu.

+1

Trong ví dụ của bạn, bạn tạo một đối tượng và nhận tất cả các thuộc tính của đối tượng và sau đó đặt cùng các thuộc tính trong đối tượng. Nó trông như thế này: 'var propValue = asObj.rooms; asObj.rooms = (int) propValue; '. Bạn thực sự muốn làm gì? Bạn có muốn sao chép tất cả các thuộc tính từ một lớp con sang một lớp cơ sở không? –

+0

@VyacheslavVolkov, tôi đã tự hỏi nếu có một cách tốt hơn để truy cập vào các thuộc tính lớp con mà không sử dụng sự phản chiếu. –

+0

Tôi không hiểu mục đích của việc này. Trong ví dụ của bạn, bạn đang mã hóa cứng tên thuộc tính con bằng 'Console.WriteLine (hsObj.rooms);'. Bạn cũng có thể loại bỏ 'hsObj = (House) hsObj.getPropertyVal (hsObj);' hoàn toàn. Sự phản chiếu hoàn toàn lãng phí. Bạn có thể đưa ra một ví dụ tốt hơn về những gì bạn đang cố gắng thực hiện không? – Dan

Trả lời

5

Trước tiên, Program.cs của bạn không thực sự "làm" những gì bạn nói bạn muốn. Có vẻ như bạn muốn một chương trình để bạn có thể thực hiện việc này:

Asset myAsset = new House(); 
myAsset.Rooms = 5; 

Nhưng, tại sao bạn thậm chí muốn làm điều đó? Nếu tài sản của bạn không phải là một nhà, nó sẽ ném một ngoại lệ, vì vậy bạn sẽ cần phải kiểm tra xem đầu tiên:

if (myAsset is House) 
    myAsset.Rooms = 5; 

Vào thời điểm đó, bạn có thể cũng chỉ cần bỏ nó vào một nhà mặc dù. Có vẻ như bạn có thể muốn sử dụng PropertyBag hoặc Dictionary thay vì thừa kế.

Tôi nghĩ bạn đang mô tả điều này. Lưu ý rằng tùy chọn 1 không thực sự hạn chế các thuộc tính nào có thể được sử dụng trên các lớp nào, vì vậy tôi đoán điều này sẽ không thực sự làm việc cho trường hợp cụ thể của bạn.

// Option 1, a Property Bag (Note: this replaces the properties on the classes) 
class Asset 
{ 
    Dictionary<string, object> myPropertyBag = new Dictionary<string, object>(); 

    public T GetProperty<T>(string property) 
    { 
     // This throws if the property doesn't exist 
     return (T)myPropertyBag[property]; 
    } 

    public void SetProperty<T>(string property, T value) 
    { 
     // This adds the property if it doesn't exist 
     myPropertyBag[property] = (object)value; 
    } 
} 

// Option 2, use a switch and override this function in derived classes 
class Asset 
{ 
    public int SomePropertyOnAsset { get; set; } 

    public virtual T GetProperty<T>(string property) 
    { 
     switch (property) 
     { 
      case "SomePropertyOnAsset": return this.SomePropertyOnAsset; 

      default: throw new ArgumentException("property"); 
     } 
    } 

    public virtual void SetProperty<T>(string property, T value) 
    { 
     switch (property) 
     { 
      case "SomePropertyOnAsset": this.SomePropertyOnAsset = (int)value; 

      default: throw new ArgumentException("property"); 
     } 
    } 
} 

class House : Asset 
{ 
    public int Rooms { get; set; } 

    public virtual T GetProperty<T>(string property) 
    { 
     switch (property) 
     { 
      case "Rooms": return this.Rooms; 

      default: return base.GetProperty<T>(property); 
     } 
    } 

    public virtual void SetProperty<T>(string property, T value) 
    { 
     switch (property) 
     { 
      case "Rooms": this.Rooms = (int)value; 
       break; 

      default: base.SetProperty<T>(property, value); 
       break; 
     } 
    } 
} 

Sau đó, đây là cách bạn sử dụng chúng:

// Option 1 
Asset asset = new House(); 
asset.SetProperty("Rooms", 5); 
var rooms = asset.GetProperty<int>("Rooms"); 

// Option 2 
Asset asset = new House(); 
asset.SetProperty("Rooms", 5); 
asset.SetProperty("SomePropertyOnAsset", 10); 
asset.SetProperty("SomethingElse", 15); // Throws ArgumentException 

Một lựa chọn thứ 3 là làm cho tài sản một DynamicObject. http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

Nếu bạn không thể hoặc không muốn thực hiện thay đổi lớn cho lớp cơ sở tài sản hoặc chạm vào mọi thực thể, có thể bạn sẽ cần phải sử dụng sự phản chiếu.

+0

Kiểm tra cập nhật của tôi. –

+0

Cảm ơn lớp DynamicObject có vẻ thú vị. –

1

Luke Gravitt có lẽ đúng. Bạn có thể chỉ muốn đúc nó vào một ngôi nhà.

House myHouse = asObj as House; 
if (myHouse != null) 
{ 
    // do some fun house stuff 
} 

Yacht myYacht = asObj as Yacht; 
if (myYacht != null) 
{ 
    // put on monocle 
} 
+0

Làm việc cho tôi. Cảm ơn! – Willy