2013-07-30 26 views
5

Moje CTO (Chief Technical Officer) poprosił mnie o wymyślenie sposobu, w którym mógłby napisać jedną funkcję w klasie bazowej i mieć dostęp do wszystkich właściwości klasa dziecka. Oto co wymyśliłem -Dostęp do właściwości klasy potomnej poprzez funkcję w klasie nadrzędnej

klasy bazowej

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; 
    } 
} 

klasa Child

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

Program.cs złożyć

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

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

Teraz działa dobrze, ale właśnie zastanawiałem się, czy istnieje lepszy sposób to zrobić w C#.

Należy pamiętać, że nie znamy jakie właściwości będą obecne w klasie dziecka, więc to będzie musiało zostać określone w czasie wykonywania.

UPDATE: co jasne, właśnie zastanawiałem się, czy istnieje lepszy sposób, aby uzyskać dostęp do właściwości klasy, jedno dziecko bez użycia refleksji. Ważne jest, aby pamiętać, że nie mamy pojęcia, jakie właściwości może mieć klasa dziecka.

AKTUALIZACJA # 2: Pracuję z produktem, który ma wiele podmiotów. Te jednostki mają różne właściwości. Chcę mieć dostęp do wszystkich tych właściwości i pracować z nimi w jednym miejscu. Ta funkcja jest właśnie taka. To jedno miejsce, z którego mogę uzyskać dostęp do wszystkich danych.

+1

W swoim przykładzie utworzysz obiekt i uzyskasz wszystkie właściwości obiektu, a następnie ustawisz te same właściwości w obiekcie. Wygląda to tak: 'var propValue = asObj.rooms; asObj.rooms = (int) propValue; '. Czego dokładnie chcesz? Czy chcesz skopiować wszystkie właściwości z klasy potomnej do klasy bazowej? –

+0

@VyacheslavVolkov, Właśnie zastanawiałem się, czy istnieje lepszy sposób uzyskania dostępu do właściwości klasy potomnej bez użycia odbicia. –

+0

Nie rozumiem celu tego. W twoim przykładzie trudno jest zakodować nazwę właściwości podrzędnej za pomocą 'Console.WriteLine (hsObj.rooms);'. Równie dobrze możesz po prostu pozbyć się linii 'hsObj = (House) hsObj.getPropertyVal (hsObj);'. Odbicie jest całkowicie zmarnowane. Czy możesz wymyślić lepszy przykład tego, co próbujesz osiągnąć? – Dan

Odpowiedz

5

Po pierwsze, Twój Program.cs właściwie nie "robi" tego, co chcesz. Wygląda na to, że chcesz program:

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

Ale dlaczego tak chciałbyś to zrobić? Jeśli składnik aktywów nie jest dom, to wyjątek, więc trzeba będzie sprawdzić, że najpierw:

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

W tym momencie, równie dobrze można po prostu rzucić go do domu, choć. Wygląda na to, że zamiast dziedziczenia możesz użyć aplikacji PropertyBag lub Dictionary.

Myślę, że to, co opisujesz, jest tym. Zauważ, że opcja 1 tak naprawdę nie ogranicza, które właściwości mogą być używane na jakich klasach, więc domyślam się, że to nie zadziała w twoim przypadku.

// 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; 
     } 
    } 
} 

Wtedy to, w jaki sposób z nich korzystać:

// 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 

3-te rozwiązaniem jest, aby aktywa A DynamicObject. http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

Jeśli nie możesz lub nie chcesz dokonać istotnej zmiany w klasie bazowej zasobu lub dotknąć każdego podmiotu, prawdopodobnie będziesz musiał użyć refleksji.

+0

Sprawdź moją aktualizację. –

+0

Dzięki klasie DynamicObject wydaje się interesujące. –

1

Luke Gravitt ma prawdopodobnie rację. Możesz po prostu rzucić go do domu.

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

Pracowałem dla mnie. Dzięki! – Willy