2015-03-05 2 views
0

У меня есть класс «TradingStrategy» с n подклассами («Strategy1, Strategy2 и т. Д.»). У меня простой пользовательский интерфейс, из которого я могу выбрать подкласс (у меня есть все подклассы класса «TradingStrategy» довольно легко). Теперь я хочу напечатать (в datagridview, listbox, combobox, не имеет значения) все общедоступные параметры выбранного подкласса.Получить свойства класса в C# (без создания экземпляра)

Я бы предпочел не создавать экземпляры подклассов.

namespace BackTester 
{ 
    class TradingStrategy 
    { 
     public string Name; 
    } 
    class MA_Test : TradingStrategy 
    { 
     new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name; 
     public int len = 12; 
     public float lots = 0.1F; 
     public bool trendFollow = true; 

     public MA_Test() 
     { 

     } 
    } 
class MA_Test2 : TradingStrategy 
    { 
     new public string Name = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name; 
     public int len = 24; 
     public float lots = 0.1F; 
     public bool trendFollow = true; 

     public MA_Test2() 
     { 

     } 
    } 
} 

С помощью этого кода я могу вставить в поле со списком каждый подкласс «TradingStrategy»

var type = typeof(TradingStrategy); 
var types = AppDomain.CurrentDomain.GetAssemblies() 
        .SelectMany(s => s.GetTypes()) 
        .Where(p => type.IsAssignableFrom(p)); 
foreach (var t in types){ 
    if (t.Name == "TradingStrategy") continue; 
    boxStrategy.Items.Add(t.Name); 
} 

Я хочу быть в состоянии, из combobox.Text, получить все имя свойства и значения соответствующий подкласс. Я думаю, что прочитал (и попробовал) каждый пост здесь и на другом форуме. Многие используют отражения.

Каков самый простой способ получить эти опоры/значения?

Благодаря

+1

Учитывая свойства не являются статичными, вы _have_ для создания экземпляра класса, чтобы читать их значения с помощью отражения. Но использование статики и отражения, скорее всего, не самый правильный способ решить вашу оригинальную проблему. – CodeCaster

+0

Кроме того, почему вы «новичок» над полем «Имя» вместо того, чтобы сделать его «виртуальным» и иметь свойства «переопределить» в подклассах? –

ответ

0

Почему бы не просто создать интерфейс ITradingStrategy:

public interface ITradingStrategy 
{ 
    string Name { get; } 
    int len { get; } 
    float lots { get; } 
    bool trendFollow { get; } 
} 

И есть все классы наследуют от интерфейса, то вытащить значения из интерфейса.

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

+0

Каждый подкласс будет иметь другой набор параметров – Prancesco

0

Чтобы получить государственные поля/свойства и их типы без инстанцировании объектов, вы можете использовать отражение следующим образом:

private static Dictionary<string, Type> GetFields(Type t) 
{ 
    var fields = new Dictionary<string, Type>(); 

    foreach (var memberInfo in t.GetMembers(BindingFlags.Instance | BindingFlags.Public)) 
    { 
     var propertyInfo = memberInfo as PropertyInfo; 
     var fieldInfo = memberInfo as FieldInfo; 
     if (propertyInfo != null) 
     { 
      fields.Add(propertyInfo.Name, propertyInfo.PropertyType); 
     } 
     if (fieldInfo != null) 
     { 
      fields.Add(fieldInfo.Name, fieldInfo.FieldType); 
     } 
    } 

    return fields; 
} 

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

private static Dictionary<string, object> GetValues(FileInfo o) 
{ 
    var values = new Dictionary<string, object>(); 

    foreach (var memberInfo in o.GetType().GetMembers(BindingFlags.Instance | BindingFlags.Public)) 
    { 
     var propertyInfo = memberInfo as PropertyInfo; 
     var fieldInfo = memberInfo as FieldInfo; 
     if (propertyInfo != null) 
     { 
      values.Add(propertyInfo.Name, propertyInfo.GetValue(o, null)); 
     } 
     if (fieldInfo != null) 
     { 
      values.Add(fieldInfo.Name, fieldInfo.GetValue(o)); 
     } 
    } 

    return values; 
} 

Следующий код является очень медленный способ, чтобы получить все типы, которые вытекают из данного типа, в связи с образом, что CLR реализует GetTypes() и тот факт, там может быть тысячи несвязанных типов в вашем коде, который заставляет стог сена искать еще больше. Единственный раз, когда вы должны использовать этот метод, - это динамически загружать сборки во время выполнения, содержащие определения объектов, которые необходимо загрузить. К сожалению, нет другого пути, чтобы получить эту информацию во время выполнения:

var type = typeof(TradingStrategy); 
var subtypes = AppDomain.CurrentDomain.GetAssemblies() 
        .SelectMany(s => s.GetTypes()) 
        .Where(p => p != type && type.IsAssignableFrom(p)); 

Я бы рекомендовал вам сохранить этот список типов где-то в вашем коде, например, в массиве, и перебрать его, когда вам нужно знать все стратегии:

private static readonly Type[] TradingStrategies = 
{ 
    typeof(Strategy1), 
    typeof(Strategy2), 
    typeof(Strategy3), 
}; 

После прочтения ответа Эрика. Если вы никогда не создадите экземпляры этих классов, вы можете сохранить эти данные в файле конфигурации и использовать что-то вроде JSON.net, чтобы прочитать его, или если вы не хотите использовать внешнюю библиотеку, также будет работать XmlSerializer. В этом случае вы должны хранить каждый MATest в качестве словаря (который хорошо поддается объекту JSON.net.Используя JSON.net, вы бы конфигурационный файл, который выглядит следующим образом:

[ 
    { 
     "MA_Test": { 
      "len": 12, 
      "lots": 0.1, 
      "trendFollow": true 
     }, 
     "MA_Test2": { 
      "len": 24, 
      "lots": 0.1, 
      "trendFollow": true 
     } 
    } 
] 

Затем прочитал его с кодом, который не выглядит как:

public JObject ReadConfig(string configPath) 
{ 
    using (var filestream = File.Open(configPath, FileMode.Open)) 
    using (var streamReader = new StreamReader(filestream)) 
    using (var jsonTextReader = new JsonTextReader(streamReader)) 
    { 
     var jsonSerializer = new JsonSerializer(); 
     return jsonSerializer.Deserialize<JObject>(jsonTextReader); 
    } 
} 
+0

. Код GetFields генерирует исключение (элемент с тем же ключом уже добавлен) – Prancesco

0

на основе кода предоставленной Вами, нет Причина наличия отдельных классов для каждого MA_Test (X DO NOT use underscores, hyphens, or any other nonalphanumeric characters.). Вместо этого они должны быть одного класса с разными свойствами (not fields).

class TradingStrategy 
{ 
    public string Name { get; set; } 
} 
class MATest : TradingStrategy 
{ 
    // this is not needed if it is inherited by TradingStragegy 
    // You should be getting a warning that you are hiding 
    // the field/property 
    // public string Name { get; set; } 

    // Should probably be more descriptive 
    // e.g. LengthInFeet... 
    public int Length { get; set; } 

    public float Lots { get; set; } 

    // I recommended boolean properties to be prefixed with 
    // Is, Can, Has, etc 
    public bool CanTrendFollow { get; set; } 
} 

// Somewhere Else... 

var MATests = new List<MATest>() 
{ 
    new MATest() 
    { 
    Name = "MATest", 
    Length = 12, 
    Lots = 0.1F, 
    CanTrendFollow = true 
    }, 
    new MATest() 
    { 
    Name = "MATest", 
    Length = 24, 
    Lots = 0.1F, 
    CanTrendFollow = true 
    }, 
} 

Теперь вместо дорогостоящего отражения и активатором, просто создать классы список раз (вручную, с помощью конфигурации или даже базы данных), и они могут быть использованы для все, что нужно.

0

Благодарим всех вас за ответы. Самый простой способ я нашел, чтобы получить свойства из indirected реализованным класса это:

 var strategy = activator.CreateInstance(Type.GetType("BackTester."+boxStrategy.Text)); 

     foreach (FieldInfo prop in strategy.GetType().GetFields(BindingFlags.Public 
      | BindingFlags.Instance)) 
     { 
      listBox1.Items.Add(prop.ToString() + " " + prop.GetValue(strategy)); 
     } 
Смежные вопросы