繁体   English   中英

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

[英]Get class properties in C# (whitout instantiating it)

我有一个类“TradingStrategy”,有n个子类(“Strategy1,Strategy2等......”)。 我有一个简单的UI,我可以从中选择一个子类(我很容易得到“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中获取相应子类的所有属性名称和值。 我想我已经在这里和其他论坛上阅读(并尝试过)每篇文章。 许多人使用反射。

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

谢谢

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

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

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

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

要在不实例化对象的情况下获取公共字段/属性及其类型,可以使用如下反射:

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存储为一个字典(它很适合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);
    }
}

根据您提供的代码 ,没有理由为每个MA_Test设置单独的类( X不要使用下划线,连字符或任何其他非字母数字字符。 )。 相反,这些应该是具有不同属性( 不是字段 )的同一个类。

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,只需创建一次列表类(手动,从配置甚至数据库),它们可以用于您需要的任何内容。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM