在C#中获取类属性(不实例化)

时间:2015-03-05 16:58:15

标签: c#

我是一个班级" TradingStrategy",有n个子类("策略1,策略2等......")。 我有一个简单的用户界面,我可以从中选择一个子类(我很容易得到" TradingStrategy"类的所有子类)。 我现在想要的是打印(在datagridview,listbox,combobox,并不重要)选择的子类的所有公共参数。

我不想实例化子类。

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中获取相应子类的所有属性名称和值。 我想我已经在这里和其他论坛上阅读(并试过)了每一篇文章。许多人使用反思。

获取这些道具/价值观的最简单方法是什么?

由于

4 个答案:

答案 0 :(得分:0)

为什么不创建一个界面ITradingStrategy:

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

让所有类继承自接口,然后从接口中提取值。

正如评论中所提到的,你必须实例化一个类的实例才能在其上设置一些值。

答案 1 :(得分: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),
};

阅读Erik的回答后。如果您永远不会实例化这些类,您可以将这些数据存储在配置文件中,并使用JSON.net之类的内容来读取它,或者如果您不想使用外部库,XmlSerializer会也工作。在这种情况下,您将每个MATest存储为一个Dictionary(它很适合JSON.net的JObject。使用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);
    }
}

答案 2 :(得分:0)

根据您提供的代码,没有理由为每个MA_TestX 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
  },
}

现在不用昂贵的Reflection和Activator,只需创建一次列表类(手动,从配置甚至数据库),它们可以用于任何你需要的。

答案 3 :(得分:0)

谢谢大家的答案。 我发现从一个间接实例化类中获取属性的最简单方法是:

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