注意:尽管我并不完全反对使用更高版本的答案,但我正在使用.Net 1.1。

我在PropertyGrid中显示一些动态生成的对象。 这些对象具有数字,文本和枚举属性。 目前,我在设置枚举的默认值时遇到问题,因此它们在列表中不会总是显示为粗体。 枚举本身也是动态生成的,除了默认值外,看起来工作正常。

首先,我想说明在引起错误的情况下如何生成枚举。 第一行使用自定义类来查询数据库。 只需将这行替换为DataAdapter或使用数据库值填充DataSet的首选方法。 我正在使用第1列中的字符串值来创建我的枚举。

private Type GetNewObjectType(string field, ModuleBuilder module, DatabaseAccess da)

//Query the database.
System.Data.DataSet ds = da.QueryDB(query);

EnumBuilder eb = module.DefineEnum(field, TypeAttributes.Public, typeof(int));

for(int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
    if(ds.Tables[0].Rows[i][1] != DBNull.Value)
    {
        string text = Convert.ToString(ds.Tables[0].Rows[i][1]);

        eb.DefineLiteral(text, i);
    }
}

return eb.CreateType();

现在介绍如何创建类型。 这很大程度上基于此处提供的示例代码。 本质上,将pFeature视为数据库行。 我们遍历各列,将列名用作新的属性名,并使用列值作为默认值; 至少这是目标。

// create a dynamic assembly and module
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "tmpAssembly";
AssemblyBuilder assemblyBuilder = System.Threading.Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule");

// create a new type builder
TypeBuilder typeBuilder = module.DefineType("BindableRowCellCollection", TypeAttributes.Public | TypeAttributes.Class);

// Loop over the attributes that will be used as the properties names in out new type
for(int i = 0; i < pFeature.Fields.FieldCount; i++)
{
    string propertyName = pFeature.Fields.get_Field(i).Name;
    object val = pFeature.get_Value(i);

    Type type = GetNewObjectType(propertyName, module, da);

    // Generate a private field
    FieldBuilder field = typeBuilder.DefineField("_" + propertyName, type, FieldAttributes.Private);

    // Generate a public property
    PropertyBuilder property =
        typeBuilder.DefineProperty(propertyName,
        PropertyAttributes.None,
        type,
        new Type[0]);

    //Create the custom attribute to set the description.
    Type[] ctorParams = new Type[] { typeof(string) };
    ConstructorInfo classCtorInfo =
        typeof(DescriptionAttribute).GetConstructor(ctorParams);

    CustomAttributeBuilder myCABuilder = new CustomAttributeBuilder(
        classCtorInfo,
        new object[] { "This is the long description of this property." });

    property.SetCustomAttribute(myCABuilder);

    //Set the default value.
    ctorParams = new Type[] { type };
    classCtorInfo = typeof(DefaultValueAttribute).GetConstructor(ctorParams);

    if(type.IsEnum)
    {
        //val contains the text version of the enum. Parse it to the enumeration value.
        object o = Enum.Parse(type, val.ToString(), true);
        myCABuilder = new CustomAttributeBuilder(
            classCtorInfo,
            new object[] { o });
    }
    else
    {
        myCABuilder = new CustomAttributeBuilder(
            classCtorInfo,
            new object[] { val });
    }

    property.SetCustomAttribute(myCABuilder);

    // The property set and property get methods require a special set of attributes:
    MethodAttributes GetSetAttr =
        MethodAttributes.Public |
        MethodAttributes.HideBySig;

    // Define the "get" accessor method for current private field.
    MethodBuilder currGetPropMthdBldr =
        typeBuilder.DefineMethod("get_value",
        GetSetAttr,
        type,
        Type.EmptyTypes);

    // Intermediate Language stuff...
    ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
    currGetIL.Emit(OpCodes.Ldarg_0);
    currGetIL.Emit(OpCodes.Ldfld, field);
    currGetIL.Emit(OpCodes.Ret);

    // Define the "set" accessor method for current private field.
    MethodBuilder currSetPropMthdBldr =
        typeBuilder.DefineMethod("set_value",
        GetSetAttr,
        null,
        new Type[] { type });

    // Again some Intermediate Language stuff...
    ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
    currSetIL.Emit(OpCodes.Ldarg_0);
    currSetIL.Emit(OpCodes.Ldarg_1);
    currSetIL.Emit(OpCodes.Stfld, field);
    currSetIL.Emit(OpCodes.Ret);

    // Last, we must map the two methods created above to our PropertyBuilder to
    // their corresponding behaviors, "get" and "set" respectively.
    property.SetGetMethod(currGetPropMthdBldr);
    property.SetSetMethod(currSetPropMthdBldr);
}

// Generate our type
Type generatedType = typeBuilder.CreateType();

最后,我们使用该类型创建它的实例并加载默认值,以便稍后可以使用PropertiesGrid显示它。

// Now we have our type. Let's create an instance from it:
object generatedObject = Activator.CreateInstance(generatedType);

// Loop over all the generated properties, and assign the default values
PropertyInfo[] properties = generatedType.GetProperties();
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(generatedType);

for(int i = 0; i < properties.Length; i++)
{
    string field = properties[i].Name;

    DefaultValueAttribute dva = (DefaultValueAttribute)props[field].Attributes[typeof(DefaultValueAttribute)];

    object o = dva.Value;

    Type pType = properties[i].PropertyType;

    if(pType.IsEnum)
    {
        o = Enum.Parse(pType, o.ToString(), true);
    }
    else
    {
        o = Convert.ChangeType(o, pType);
    }

    properties[i].SetValue(generatedObject, o, null);
}

return generatedObject;

但是,当我们尝试获取枚举的默认值时,这会导致错误。 未设置DefaultValueAttribute dva,因此当我们尝试使用它时会导致异常。

如果我们更改此代码段:

    if(type.IsEnum)
    {
        object o = Enum.Parse(type, val.ToString(), true);
        myCABuilder = new CustomAttributeBuilder(
            classCtorInfo,
            new object[] { o });
    }

对此:

    if(type.IsEnum)
    {
        myCABuilder = new CustomAttributeBuilder(
            classCtorInfo,
            new object[] { 0 });
    }

获取DefaultValueAttribute dva没问题; 但是,该字段然后在PropertiesGrid中以粗体显示,因为它与默认值不匹配。

任何人都可以弄清楚为什么在将默认值设置为生成的枚举时无法获取DefaultValueAttribute吗? 您可能会猜到,我仍然是反射的新手,所以这对我来说是相当新的。

谢谢。

更新:针对alabamasucks.blogspot,使用ShouldSerialize当然可以解决我的问题。 我能够使用普通的类创建方法; 但是,我不确定如何对生成的类型执行此操作。 据我所知,我将需要使用MethodBuilder并生成IL以检查该字段是否等于默认值。 听起来很简单。 我想用IL代码表示:

public bool ShouldSerializepropertyName()
{
     return (field != val);
}

我可以使用ildasm.exe从类似的代码中获取IL代码,但是我有几个问题。 如何在IL代码中使用val变量? 在我的示例中,我使用了一个值为0的int。

IL_0000:  ldc.i4.s   0
IL_0002:  stloc.0
IL_0003:  ldloc.0
IL_0004:  ldarg.0
IL_0005:  ldfld      int32 TestNamespace.TestClass::field
IL_000a:  ceq
IL_000c:  ldc.i4.0
IL_000d:  ceq
IL_000f:  stloc.1
IL_0010:  br.s       IL_0012
IL_0012:  ldloc.1
IL_0013:  ret

这肯定会变得棘手,因为IL对于每种类型都有不同的加载命令。 当前,我使用整数,双精度型,字符串和枚举,因此代码必须根据类型自适应。

有谁知道如何做到这一点? 还是我朝着错误的方向前进?

===============>>#1 票数:3

我不确定如何使该属性起作用,但是还有另一个选项可能更容易。

除了检查DefaultValueAttribute外,PropertyGrid还使用反射来查找名为“ ShouldSerializeProperty Name”的方法,其中[Property Name]是所讨论属性的名称。 如果该属性设置为非默认值,则此方法应返回一个布尔值,该值为true,否则为false。 使用反射创建返回正确值然后修正属性的方法可能会更容易。

===============>>#2 票数:2

您应该尝试使用带有字符串和Type参数的DefaultValueAttribute,并传入字符串枚举值(val.ToString)和枚举的类型。

  ask by translate from so

未解决问题?本站智能推荐:

1回复

枚举Outlook ContactItem属性

我试图使用以下代码枚举Microsoft.Office.Interop.Outlook.ContactItem对象的属性(让我们称之为ci): 我实际上尝试了几种BindingFlag值的组合,但是没有返回任何属性。 这就是ContactItem的定义方式:使用System.Run
2回复

有没有办法迭代和反映枚举中包含的成员名称和值?

假设我有以下enum : 我想知道是否有办法迭代所有的Colors成员来找到成员名称及其值。
4回复

如何迭代C#对象,查找特定类型的所有实例,以便构建这些实例的单独列表?

我需要有点类似于这个问题 ,除了它需要更深入地探索源对象。 这是一个代码示例: 从Analyzed的实例中,我想提取所有Target实例。 为了便于探索,我们可以假设以下内容: 仅浏览属性。 没有无限的参考循环。 就目前而言, EasyOne很简单,
1回复

如何动态或在运行时设置PropertyGrid的DefaultValueAttribute?

我正在定义一个与PropertyGrid控件一起使用的自定义类。 比如,其中一个属性定义如下: 如您所见, DefaultValueAttribute定义属性的默认值。 这种默认值用于两种情况: 如果此属性值从默认值更改,则PropertyGrid控件将以粗体显示,并且
1回复

如何反映应用于枚举类型本身的自定义属性

我有一个自定义属性,我想将其应用于枚举类型本身,但是我无法确定正确的路径以获取适当的* Info来公开该属性。 像这样 我熟悉从枚举值中反映出DescriptionAttribute的更多“惯用”方法。 我一直在做这种事情,没问题。 与以下类型的情况一样。 我敢肯定这很
2回复

有人知道快速获取枚举值的自定义属性吗?

这可能是最好的例子。 我有一个属性的枚举: 我想从实例中获取这些属性: 由于这是使用反射我希望有些慢,但是当我已经拥有它的实例时,将枚举值转换为字符串(它反映了名称)似乎很麻烦。 有没有人有更好的方法?
3回复

获取枚举的自定义属性的属性

我的项目有这个BookDetails属性: 以及此处的属性代码: 如何获取给定书籍的作者? 试过这个凌乱的代码,但它不起作用: 谢谢,必须有比我上面尝试的更好的方式。
2回复

如何根据项目中的类创建枚举变量

我正在编写一个DLL,它将公开一个这样的方法: 目前,FileType是一个枚举,如下所示: 这将表示可以转换给定类型文件的每个类。 我将基于一个接口有几个不同的类,每个类都可以处理特定类型的文件。 我没有像上面那样拥有枚举,而是每次添加一个类时我必须手动更改它,以便调用
2回复

是类的子类还是对象

注意:我在问子类,而不是派生类。 基本上,我需要做的是检查对象的属性,并查找具有特定属性集的属性。 我的问题是很多属性来自子类 现在,我正在尝试按以下方式进行操作...但是由于注释中指出的原因,它将无法正常工作 有任何想法吗?
2回复

c#如何从自定义属性获取枚举? [重复]

这个问题已经在这里有了答案: 如何获取枚举的自定义属性值? 7个答案 这是MyEnum 我如何获取具有特定CountryCodeAttr的枚举? 例如来自属性Currency?