当前位置:  开发笔记 > 编程语言 > 正文

C#类可以从其接口继承属性吗?

如何解决《C#类可以从其接口继承属性吗?》经验,为你挑选了4个好方法。

这似乎意味着"不".哪个是不幸的.

[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class,
 AllowMultiple = true, Inherited = true)]
public class CustomDescriptionAttribute : Attribute
{
    public string Description { get; private set; }

    public CustomDescriptionAttribute(string description)
    {
        Description = description;
    }
}

[CustomDescription("IProjectController")]
public interface IProjectController
{
    void Create(string projectName);
}

internal class ProjectController : IProjectController
{
    public void Create(string projectName)
    {
    }
}

[TestFixture]
public class CustomDescriptionAttributeTests
{
    [Test]
    public void ProjectController_ShouldHaveCustomDescriptionAttribute()
    {
        Type type = typeof(ProjectController);
        object[] attributes = type.GetCustomAttributes(
            typeof(CustomDescriptionAttribute),
            true);

        // NUnit.Framework.AssertionException:   Expected: 1   But was:  0
        Assert.AreEqual(1, attributes.Length);
    }
}

类可以从接口继承属性吗?或者我在这里咆哮错误的树?



1> Marc Gravell..:

不会.无论何时在派生类中实现接口或覆盖成员,都需要重新声明属性.

如果您只关心ComponentModel(不是直接反射),则有一种方法([AttributeProvider])建议来自现有类型的属性(以避免重复),但它仅对属性和索引器使用有效.

举个例子:

using System;
using System.ComponentModel;
class Foo {
    [AttributeProvider(typeof(IListSource))]
    public object Bar { get; set; }

    static void Main() {
        var bar = TypeDescriptor.GetProperties(typeof(Foo))["Bar"];
        foreach (Attribute attrib in bar.Attributes) {
            Console.WriteLine(attrib);
        }
    }
}

输出:

System.SerializableAttribute
System.ComponentModel.AttributeProviderAttribute
System.ComponentModel.EditorAttribute
System.Runtime.InteropServices.ComVisibleAttribute
System.Runtime.InteropServices.ClassInterfaceAttribute
System.ComponentModel.TypeConverterAttribute
System.ComponentModel.MergablePropertyAttribute


@Ryan - 确定:用于描述界面.例如,服务合同.
嗯.我刚刚注意到问题是从接口继承属性而不是从基类继承属性.
Marc(和@Rune):是的,OP是关于接口的.但你的答案的第一句可能会令人困惑:"......或派生类中的成员......" - 这不一定是真的.您可以让您的类从其基类继承属性.你只能用接口做到这一点.另见:http://stackoverflow.com/questions/12106566/attribute-on-interface-members-does-not-work

2> tanascius..:

您可以定义一个有用的扩展方法......

Type type = typeof(ProjectController);
var attributes = type.GetCustomAttributes( true );

这是扩展方法:

/// Searches and returns attributes. The inheritance chain is not used to find the attributes.
/// The type of attribute to search for.
/// The type which is searched for the attributes.
/// Returns all attributes.
public static T[] GetCustomAttributes( this Type type ) where T : Attribute
{
  return GetCustomAttributes( type, typeof( T ), false ).Select( arg => (T)arg ).ToArray();
}

/// Searches and returns attributes.
/// The type of attribute to search for.
/// The type which is searched for the attributes.
/// Specifies whether to search this member's inheritance chain to find the attributes. Interfaces will be searched, too.
/// Returns all attributes.
public static T[] GetCustomAttributes( this Type type, bool inherit ) where T : Attribute
{
  return GetCustomAttributes( type, typeof( T ), inherit ).Select( arg => (T)arg ).ToArray();
}

/// Private helper for searching attributes.
/// The type which is searched for the attribute.
/// The type of attribute to search for.
/// Specifies whether to search this member's inheritance chain to find the attribute. Interfaces will be searched, too.
/// An array that contains all the custom attributes, or an array with zero elements if no attributes are defined.
private static object[] GetCustomAttributes( Type type, Type attributeType, bool inherit )
{
  if( !inherit )
  {
    return type.GetCustomAttributes( attributeType, false );
  }

  var attributeCollection = new Collection();
  var baseType = type;

  do
  {
    baseType.GetCustomAttributes( attributeType, true ).Apply( attributeCollection.Add );
    baseType = baseType.BaseType;
  }
  while( baseType != null );

  foreach( var interfaceType in type.GetInterfaces() )
  {
    GetCustomAttributes( interfaceType, attributeType, true ).Apply( attributeCollection.Add );
  }

  var attributeArray = new object[attributeCollection.Count];
  attributeCollection.CopyTo( attributeArray, 0 );
  return attributeArray;
}

/// Applies a function to every element of the list.
private static void Apply( this IEnumerable enumerable, Action function )
{
  foreach( var item in enumerable )
  {
    function.Invoke( item );
  }
}


更新:

以下是SimonD在评论中提出的较短版本:

private static IEnumerable GetCustomAttributesIncludingBaseInterfaces(this Type type)
{
  var attributeType = typeof(T);
  return type.GetCustomAttributes(attributeType, true).
    Union(type.GetInterfaces().
    SelectMany(interfaceType => interfaceType.GetCustomAttributes(attributeType, true))).
    Distinct().Cast();
}


非常好,我个人使用这个的较短版本,现在:private static IEnumerable GetCustomAttributesIncludingBaseInterfaces (此Type类型){var attributeType = typeof(T); return type.GetCustomAttributes(attributeType,true).Union(type.GetInterfaces().SelectMany(interfaceType => interfaceType.GetCustomAttributes(attributeType,true))).Distinct().Cast (); }

3> Roger Lipsco..:

Brad Wilson关于此的文章:接口属性!=类属性

总结一下:类不从接口继承,它们实现它们.这意味着属性不会自动成为实现的一部分.

如果需要继承属性,请使用抽象基类,而不是接口.



4> Peter Gluck..:

虽然C#类不从其接口继承属性,但在ASP.NET MVC3中绑定模型时有一个有用的替代方法.

如果将视图的模型声明为接口而不是具体类型,则视图和模型绑定器将应用属性(例如,[Required][DisplayName("Foo")]在渲染和验证模型时从接口应用):

public interface IModel {
    [Required]
    [DisplayName("Foo Bar")]
    string FooBar { get; set; }
} 

public class Model : IModel {
    public string FooBar { get; set; }
}

然后在视图中:

@* Note use of interface type for the view model *@
@model IModel 

@* This control will receive the attributes from the interface *@
@Html.EditorFor(m => m.FooBar)

推荐阅读
保佑欣疼你的芯疼
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有