【问题标题】:Referring to class members as enumerations in C#在 C# 中将类成员称为枚举
【发布时间】:2015-08-04 06:14:24
【问题描述】:

有没有办法将类“成员”作为一等值传递?

public class Bike {
    public Color BikeColour { get; set; }
    public bool  IsGirlsBike { get; set; }
}

然后我想引用字段名称,没有任何对象的概念。

我想我想要的是一个枚举之类的东西:

public enum BikeFields {BikeColour, IsGirlsBike};

但没有明确定义。

有没有办法在 C# 中做到这一点?

编辑:抱歉如此含糊;我希望能够将类成员称为一流的事物(几乎就像绑定类型)。

Set<Bike:T> whichFieldsHaveBeenDrawn = new Set<Bike:T>();

Bike:T 未定义,我希望下图能清楚地说明这种新类型的工作原理。

whichFieldsHaveBeenDrawn.Include(Bike.BikeColour);

var remainingFields = Set.Subtract(Bike.GetAllFields(), whichFieldsHaveBeenDrawn);

Bike b = new Bike();
foreach (var field in remainingFields) { Draw(field, b); }

我想我可以通过反射来做到这一点,但我希望它们在编译时合格......

【问题讨论】:

  • 你将如何在你的代码中使用它们?
  • 您要解决什么问题,这个“枚举”将成为解决方案的一部分?目前这有点太抽象了。你已经用反射标记了这个,所以我假设你知道反射可以做什么(例如MemberInfo
  • 您的问题在当前形式下毫无意义。需要更多细节。
  • 请查看已编辑的问题 -
  • 如上所述,您可以使用反射来获取属性的名称,然后与 EnumBuilder 结合,您可以动态创建枚举(参见stackoverflow.com/a/24804723/174929

标签: c# .net reflection metadata


【解决方案1】:

你不能同时拥有一个静态类型的 Enum 和一个类,因为它们是在同一个步骤中编译的。所以你需要两个步骤,第一个拥有类然后生成相应的 Enum。分两步实现此目的的一种方法是使用 t4 模板,如下所示:

1. 创建一个类库(比方说叫做 ClassLibrary)。这将包含您的 Bike 类。

2. 在控制台应用程序(或您可能需要的任何其他类型的项目)中添加一个 t4 文本模板,如下所示:

<#@ template debug="true" hostspecific="false" language="C#" #>
<#@ assembly name="$(TargetDir)\ClassLibrary.dll" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="ClassLibrary" #>
<#@ output extension=".generated.cs" #>

namespace SO_31801914
{

<#
    var classes = new Type[] { typeof(ClassLibrary.Bike) };

    foreach (var cls in classes)
    {
#>
    public enum <#=cls.Name#>Enum
    {
<#      var props = cls.GetProperties();        
        for (int i = 0 ; i < props.Length; i++)
        {
            var prop = props[i];
            bool skipComma = false;
            if (i == props.Length - 1)
            {
                skipComma = true;
            }
#>
            <#=prop.Name#><#=skipComma ? string.Empty : ","#>
<#
        }
#>
    }
<#
    }
#>
}

结果将是:

namespace SO_31801914
{

    public enum BikeEnum
    {
        BikeColour,
        IsGirlsBike
    }
}

Build ClassLibrary 然后右键单击模板并单击“运行自定义工具”。在TemplateName.generated.cs 中你会得到上述结果。

【讨论】:

  • 感谢@tomab,这是最接近我的想法的解决方案——我希望编译器通过编程语言对用户更加开放。
【解决方案2】:

只是把它扔在那里。但是如果你想直接通过名字来引用成员......为什么不使用nameof呢?

class Foo
{
    public int A { get; set; }
    public int B { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var rendered = new List<string>();

        if (!rendered.Contains(nameof(Foo.A)))
        {
            //Do something
            rendered.Add(nameof(Foo.A));
        }
    }
}

如果你真的想要一个枚举:

public enum FooFields
{
    A,
    B
}

var enumA = Enum.Parse(typeof (FooFields), nameof(Foo.A));

【讨论】:

  • 如果无法使用 C# 6.0,则可能无法使用 nameof
【解决方案3】:

您可以将属性及其值转换为字典

var bike = new Bike() { BikeColour = Color.Red, IsGirlsBike = true };
var props = bike.GetType().GetProperties()
           .ToDictionary(p => p.Name, p => p.GetValue(bike, null));

编辑

如果我理解正确,你想写一个类似这样的代码

var props = GetAllProperties<Bike>()
            .Except(new[] { GetProperty<Bike>(x => x.BikeColour) });
Draw(bike, props);

public IEnumerable<PropertyInfo> GetAllProperties<T>()
{
    return typeof(T).GetProperties();
}

public PropertyInfo GetProperty<T>(Expression<Func<T,object>> expr)
{
    var uExpr = expr.Body as UnaryExpression;
    var memberExpr = uExpr.Operand as MemberExpression;
    return memberExpr.Member as PropertyInfo;
}

public Dictionary<string,object> GetValues<T>(T obj, IEnumerable<PropertyInfo> props)
{
    return props.ToDictionary(p => p.Name, p => p.GetValue(obj, null));
}

void Draw(Bike b, IEnumerable<PropertyInfo> properties)
{
    var values = GetValues(b, properties);
}

【讨论】:

  • 然后呢?这不是真正的枚举,它不会做与枚举相同的事情。
  • OP 说,I guess what I want is something like an enum,所以他不确定。我展示了动态的方式。它有什么问题。
  • 是的@EZI - 像这样的东西......但编译时间检查。请查看已编辑的问题。
  • 感谢@EZI - GetProperty 非常有趣;除了 nameof() 之外,这里提出的所有答案都是运行时的 - 即如果不运行程序就无法检查它们。我希望这是有道理的,tomab 下面的答案最接近我的想法——这些信息保存在编译器的某个地方——但我怀疑它被扔掉了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 2015-11-19
  • 2018-11-05
  • 1970-01-01
  • 2014-08-20
相关资源
最近更新 更多