Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/331.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我可以在分部类中定义属性,然后在另一个分部类中用属性标记它们吗?_C#_Attributes_Code Generation_Partial Classes - Fatal编程技术网

C# 我可以在分部类中定义属性,然后在另一个分部类中用属性标记它们吗?

C# 我可以在分部类中定义属性,然后在另一个分部类中用属性标记它们吗?,c#,attributes,code-generation,partial-classes,C#,Attributes,Code Generation,Partial Classes,有没有办法生成这样的代码文件: public partial class A { public string a { get; set; } } 然后在另一个文件中: public partial class A { [Attribute("etc")] public string a { get; set; } } 这样我就可以从数据库中生成一个类,然后使用一个未生成的文件来标记它?不是这样;编译器将抱怨该成员是在多个部分中定义的。但是,由于

有没有办法生成这样的代码文件:

public partial class A 
{
    public string a { get; set; }
}
然后在另一个文件中:

public partial class A 
{
    [Attribute("etc")]
    public string a { get; set; }
}

这样我就可以从数据库中生成一个类,然后使用一个未生成的文件来标记它?

不是这样;编译器将抱怨该成员是在多个部分中定义的。但是,由于自定义属性的使用本质上是反射性的,因此可以定义一个“元数据”类并使用它来包含装饰器

public class A
{
   public string MyString;
}

public class AMeta
{
   [TheAttribute("etc")]
   public object MyString;
}

...

var myA = new A();
var metaType = Type.GetType(myA.GetType().Name + "Meta");
var attributesOfMyString = metaType.GetMember("MyString").GetCustomAttributes();

我在斯科特·古思里(Scott Guthrie)的一篇文章(接近尾声)中看到过类似的情况——不过我自己没有尝试过。


以下是我在此类情况下使用的解决方案。当您拥有要用属性装饰的自动生成的类时,它非常有用。假设这是自动生成的类:

public partial class UserProfile
{
    public int UserId { get; set; }
    public string UserName { get; set; }
    public string Firstname { get; set; }
    public string Lastname { get; set; }
}
比如说,我想添加一个属性来指定UserId是键。然后,我会在另一个文件中创建一个分部类,如下所示:

[Table("UserProfile")]
[MetadataType(typeof(UserProfileMetadata))]
public partial class UserProfile
{
    internal sealed class UserProfileMetadata
    {
        [Key]
        [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
        public int UserId { get; set; }
    }
}
这是我的答案
不同的类文件,或者您可以将元数据组合到同一个文件中,但名称空间保持不变。这样它们就可以清楚地看到彼此

请记住,当您更新模型(如添加更多列)时,您也必须更新项目类

--your model class
public partial class A {
    public string a {get; set;}
}

--your project class 
public class Ametadata {
     [Attribute("etc")]
     public string a {get; set;}
}


[MetadataType(typeof(Ametadata))]
public partial class A
{
}

您需要为
a
类定义一个分部类,如下例所示

using System.ComponentModel.DataAnnotations;

// your auto-generated partial class
public partial class A 
{
    public string MyProp { get; set; }
}

[MetadataType(typeof(AMetaData))]
public partial class A 
{

}

public class AMetaData
{
    [System.ComponentModel.DefaultValue(0)]
    public string MyProp { get; set; }
}

多少是“从数据库中生成的”?只有属性定义,还是代码?简短回答,否。长回答,重复的。@snemark:仅属性定义,我计划手工编写任何其他代码。你能用接口+实现拆分而不是部分类吗?从数据库生成接口,实现(并添加属性)在实现中。是的,这是可能的,但通过使用元数据,然后让另一个部分继承该元数据。将属性添加到其属性的参与者也是使用这些属性的人,因此知道如何查找神奇的“元”类?根据我的经验,这是非常常见的。这对于现有的面向方面的框架不起作用,但是如果您使用自定义验证属性来装饰您的域,那么您就是在寻找这些属性的人,并且可以定义它们的位置。我的团队已经在我们的一个项目上完成了这项工作。主要的缺点是不寻找其他类别;它在开发时维护两个并行类,一个是函数类,另一个是装饰类。如果您能够首先定义部分字段/属性,那么这在部分类中也是一个问题。@KirkWoll在我看来,这是一个好问题。我认为这是一个很好的理由,可以将元类与注释类放在同一个文件中,甚至可以放在文件的顶部,因此,其他编码人员将更有可能找到该代码。这个答案值得一提,但它不是OP提出的问题的一般解决方案。属性的使用者仍然需要知道如何查找元数据类——也就是说,这些属性不会由Attribute.GetCustomAttribute(…)返回。(幸运的是,对于许多用例来说,消费者是由MS编写的,在某些情况下,这会起作用。)此解决方案无法解决问题。为什么我们要在另一个文件中装饰成员?因为每次设计器运行时都会覆盖该类。因此,您的属性
[MetaDataType…
将在每次设计器启动时清除runs@Desolator-这样做的目的是不要将
MetadataType
属性放在设计器生成的文件中,而是将其放在另一个文件中,在该文件中定义了分部类
Person
。此解决方案的问题是该类应该是分部的注意。我知道你可以用多个文件中的属性来修饰部分类,甚至可以在其声明中添加接口和继承类,但我没有连接到
MetadataType
属性。做得好!如果我想向
UserProfile
的构造函数添加属性呢?
MetadataType
.NET Core中不存在。NET Core使用
ModelMetadataType
@Dave支持应该在.NET Core 3.0中提供
using System.ComponentModel.DataAnnotations;

// your auto-generated partial class
public partial class A 
{
    public string MyProp { get; set; }
}

[MetadataType(typeof(AMetaData))]
public partial class A 
{

}

public class AMetaData
{
    [System.ComponentModel.DefaultValue(0)]
    public string MyProp { get; set; }
}