2013-07-30 3 views
5

Мой технический директор (Главный технический директор) попросил меня придумать способ, чтобы он мог написать одну единственную функцию в базовом классе и получить доступ ко всем свойствам класс ребенка. Вот что я придумал -Доступ к свойствам дочернего класса через функцию в родительском классе

Базовый класс

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

Детский класс

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

Program.cs файл

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

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

Теперь это прекрасно работает, но мне просто интересно, есть ли лучший способ сделать это на C#.

Отметьте, что Мы не знаем Какие свойства будут присутствовать в дочернем классе, поэтому это нужно будет определить во время выполнения.

UPDATE: разъясняя, мне было просто интересно, если есть лучший способ получить доступ к свойствам класса ребенка, один без использования отражения. Важно отметить, что мы понятия не имеем, какие свойства имеет дочерний класс.

ОБНОВЛЕНИЕ # 2: Я работаю с продуктом, который имеет множество объектов. Эти объекты имеют разные свойства. Я хочу иметь доступ и работать со всеми этими свойствами в одном месте. Эта функция в точности такова. Это одно место, откуда я могу получить доступ ко всем данным.

+1

В вашем примере вы создаете объект и получаете все свойства объекта, а затем устанавливаете те же свойства в объекте. Это выглядит так: 'var propValue = asObj.rooms; asObj.rooms = (int) propValue; '. Что именно вы хотите? Вы хотите скопировать все свойства из дочернего класса в базовый класс? –

+0

@VyacheslavVolkov, мне просто интересно, есть ли лучший способ доступа к свойствам дочернего класса без использования рефлексии. –

+0

Я не понимаю цели этого. В вашем примере вы жестко кодируете имя дочернего объекта с помощью 'Console.WriteLine (hsObj.rooms);'. Вы можете просто избавиться от hsObj = (House) hsObj.getPropertyVal (hsObj); 'вообще. Отражение полностью потеряно. Можете ли вы придумать лучший пример того, что вы пытаетесь выполнить? – Dan

ответ

5

Во-первых, ваш Program.cs фактически не «делает» то, что вы говорите, что хотите. Похоже, что вы хотите программу, так что вы можете сделать это:

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

Но, почему бы вам даже хочу сделать это в любом случае? Если актив не дом, он будет бросать исключение, так что вам нужно будет проверить, что первое:

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

В этот момент, вы можете также просто бросить его в дом, хотя. Похоже, вы можете использовать PropertyBag или Dictionary вместо наследования.

Я думаю, что вы описываете это. Обратите внимание, что опция 1 на самом деле не ограничивает, какие свойства можно использовать для каких классов, поэтому я предполагаю, что это не будет работать для вашего конкретного случая.

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

Тогда это то, как вы их используете:

// 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-й вариант, чтобы сделать актив DynamicObject.

Если вы не можете или не хотите совершать серьезные изменения в базовом классе вашего актива или касаться каждого объекта, вам, вероятно, потребуется использовать отражение.

+0

Проверьте мое обновление. –

+0

Спасибо, класс DynamicObject кажется интересным. –

1

Люк Гравитт, вероятно, прав. Вы могли бы просто бросить его в дом.

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

Работал для меня. Благодаря! – Willy

Смежные вопросы