在C#中将类成员称为枚举类型

4
有没有一种方法可以将类'members'作为一等值进行传递?
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); }

我认为可以使用反射来实现这一点,但我希望在编译时进行限定...


你将如何在你的代码中使用它们? - Nikhil Chavan
4
你试图解决什么问题,让这个“枚举”成为解决方案的一部分?目前这有点抽象。你已经加了反射的标签,我猜你知道反射可以做些什么(比如MemberInfo)。 - Damien_The_Unbeliever
您的问题在当前形式下没有意义。需要更多细节。 - Sam Axe
抱歉,您的问题已被编辑,请提供新的内容以便我进行翻译。 - wmercer
如上所述,您可以使用反射来获取属性的名称,然后与 EnumBuilder 结合使用,动态创建枚举(请参见 https://dev59.com/yXRA5IYBdhLWcg3wtwOe#24804723)。 - nieve
3个回答

2
您不能同时拥有一个静态类型的枚举和一个类,因为它们在编译时会被编译在同一步骤中。因此,您需要两个步骤,第一个步骤是创建类,然后生成相应的枚举。通过使用像这样的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
    }
}

构建 ClassLibrary,然后右键单击模板并点击 "运行自定义工具"。在 TemplateName.generated.cs 文件中,您将获得上述结果。


谢谢@tomab,这是我想到的最接近的解决方案 - 我希望编译器通过编程语言对用户更加开放。 - wmercer

1
你可以将属性及其值转换为字典。
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);
}

然后呢?那不是真正的枚举,也不能像枚举一样做同样的事情。 - Robert Harvey
OP说,“我想要的大概就是枚举类型”,所以他不确定。我展示了动态方式。这有什么问题吗? - EZI
是的 @EZI - 类似这样... 但在编译时进行检查。请参见修改后的问题。 - wmercer
感谢@EZI - GetProperty<T>非常有趣;除了nameof()之外,这里提出的所有答案都是运行时的 - 也就是说,它们不能在不运行程序的情况下进行检查。我希望这有意义,tomab在下面的回答中最接近我所想的 - 这些信息在编译器中被保留 - 但我怀疑它会被丢弃。 - wmercer

1

仅提出这个想法。但是如果您想直接按名称引用成员...为什么不使用“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 - tomab

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接