18

MVC 属性に関する最近の質問で、アクション メソッドで HttpPost および HttpDelete 属性を使用すると、リクエスト タイプが許可されるか、または許可されないリクエストのいずれかになるかどうかという質問がありました (同時に Post と Delete の両方になることはできないため)。 )。HttpPostAttribute と HttpDeleteAttribute の両方が派生する ActionMethodSelectorAttribute が装飾されていることに気付きました

[AttributeUsage(AttributeTargets.Method,
                AllowMultiple = false,
                Inherited = true)]

このため、同じメソッドで HttpPost と HttpDelete の両方を許可しないと予想していましたが、コンパイラは文句を言いません。私の限られたテストでは、基本クラスでの属性の使用は単に無視されていることがわかりました。AllowMultiple は、同じ属性の 2 つがメソッド/クラスに適用されることを許可しないように見えるだけであり、それらの属性が倍数を許可しないように構成された同じクラスから派生するかどうかを考慮していないようです。さらに、基本クラスでの属性の使用は、派生クラスでの属性の使用を変更することを妨げるものではありません。だとすれば、基本属性クラスに値を設定する意味さえありますか? それは単なる助言ですか、それともそれらがどのように機能するかについて何か基本的なことが欠けていますか?

参考までに、両方を使用すると、基本的にその方法が考慮されなくなることがわかりました。属性は個別に評価され、同時に Post と Delete の両方になることはできないため、そのうちの 1 つがメソッドがリクエストに対して無効であることを常に示します。

4

3 に答える 3

14

ベース アトリビュートを設定AllowMultipleすると、基本的に、そこから派生するすべてのアトリビュートのデフォルトが設定されます。ベース アトリビュートから派生するすべての属性で複数のインスタンスを許可する場合は、[AttributeUsage]この効果のアトリビュートをベース アトリビュートに適用することで重複を避けることができ、すべての派生アトリビュートに対して同じことを行う必要がなくなります。

たとえば、これを許可したいとします。

public abstract class MyAttributeBase : Attribute
{
}

public sealed class FooAttribute : MyAttributeBase
{
}

public sealed class BarAttribute : MyAttributeBase
{
}

[Foo]
[Foo]
[Bar]
[Bar]
public class A
{
}

現状では、カスタム属性はデフォルトで複数のインスタンスを許可しないため、これはコンパイラ エラーを生成します。[AttribteUsage]を両方[Foo]に適用すると、次の[Bar]ようになります。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class FooAttribute : MyAttributeBase
{
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public sealed class BarAttribute : MyAttributeBase
{
}

ただし、代わりに base 属性に適用することもできます。

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public abstract class MyAttributeBase : Attribute
{
}

public sealed class FooAttribute : MyAttributeBase
{
}

public sealed class BarAttribute : MyAttributeBase
{
}

どちらのアプローチにも同じ直接的な効果があります (両方の[Foo]との複数のインスタンスが許可されます) が、2 番目のアプローチには、その設定をオーバーライドする独自の属性がない限り、派生する他の属性[Bar]複数のインスタンスを許可するという間接的な効果もあります。[MyAttribute][AttributeUsage]

于 2010-04-29T13:47:05.993 に答える
0

AllowMultipleは、その特定の属性が複数回使用されることを許可/禁止します。他の属性を組み合わせることができるかどうかには影響しません。

したがって、たとえば、メソッドの名前変更を有効にするか無効にするかを制御するObfuscationAttributeがある場合、ユーザーがこれを実行できないようにする必要があります。

[Obfuscation("DisableRenaming")]
[Obfuscation("EnableRenaming")]
void MyMethod()
{
}

この場合、難読化を有効または無効にすることはできないため、AllowMultiple = falseを使用して、メソッドがこの特定の属性で1回だけマークされるようにします。

相互に排他的な場合、仮想的に実行できるのは、HttpSettingsと呼ばれる単一の属性を使用することです。この属性は、PostまたはDeleteの「モード」に適用されるかどうかを示すパラメーターを取ります。これは、オプションの相互排他性を強制するためにAllowMultiple=falseになる可能性があります。

于 2010-04-15T21:41:02.657 に答える
0

簡単なテストをしましょう:

using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Reflection;

namespace TestAttrs {
    public abstract class BaseAttribute : Attribute { 
        public string text; 
    }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class MultipleInheritedAttribute : BaseAttribute {  }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
    public class MultipleNonInheritedAttribute : BaseAttribute {  }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class SingleInheritedAttribute : BaseAttribute {  }

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    public class SingleNonInheritedAttribute : BaseAttribute {  }

    public class BaseClass {
        [MultipleInherited(text = "MultipleInheritedBase")]
        [MultipleNonInherited(text = "MultipleNonInheritedBase")]
        [SingleInherited(text = "SingleInheritedBase")]
        [SingleNonInherited(text = "SingleNonInheritedBase")]
        public virtual void Method() { ; }
    }

    public class DerivedClass : BaseClass {
        [MultipleInherited(text = "MultipleInheritedDerived")]
        [MultipleNonInherited(text = "MultipleNonInheritedDerived")]
        [SingleInherited(text = "SingleInheritedDerived")]
        [SingleNonInherited(text = "SingleNonInheritedDerived")]
        public override void Method() {
            base.Method();
        }
    }

    [TestClass]
    public class AttributesTest {
        [TestMethod]
        public void TestAttributes() {
            MemberInfo mi = typeof(DerivedClass).GetMember("Method")[0];
            object[] attrs = mi.GetCustomAttributes(true);

            string log = "";
            foreach(BaseAttribute attr in attrs) {
                log += attr.text+"|";
            }
            Assert.AreEqual("MultipleInheritedDerived|SingleInheritedDerived|SingleNonInheritedDerived|MultipleNonInheritedDerived|MultipleInheritedBase|", log);
        }
    }
}

ご覧のとおり、属性がマークされInherted=trueている場合は派生クラスに対して返されますが、継承されたメソッドが同じ属性でマークされている場合は抑制されますAllowMultiple=false. したがって、私たちのテストでは、ログ文字列には「MultipleInheritedDerived」と「MultipleInheritedBase」の両方が含まれていますが、「SingleInheritedBase」は含まれていません。

それであなたの質問に答えてください - ポイントは何ですか?この組み合わせにより、属性を気にせずにオーバーライドできる仮想メソッドを備えた基本コントローラーを使用できますが (基本メソッドから取得されます)、同時に必要に応じてオーバーライドすることもできます。HttpPostAttribute はパラメーターを持たないため、良い例ではありませんが、他の属性はそのような設定の恩恵を受けることができます。

また、属性を消費するコードに注意してください。

       object[] attrs = mi.GetCustomAttributes(true);

継承された属性に関心があることを指定します。書いたら

       object[] attrs = mi.GetCustomAttributes(false);

結果には、使用設定に関係なく、4 つの属性が含まれます。そのため、開発者は継承属性の使用設定を無視することができます。

于 2010-04-23T00:43:03.647 に答える