如何创建一个RangeAttribute为WindowsForms? [英] How to create a RangeAttribute for WindowsForms?

查看:230
本文介绍了如何创建一个RangeAttribute为WindowsForms?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个名为元数据属性 RangeAttribute 不喜欢 PostSharp 外部工具中的这个答案,因为它需要的库的付费版本。

I would like to create a metadata attribute called RangeAttribute without external tools like PostSharp as seen in this answer because it requires the paid version of the library.

这是我发现这个唯一的官方信息的这个MSDN文档,但荒谬的页面只解释了如何声明类和继承......仅此而已,所以我更失去了。

The only official information that I've found about this is this MSDN documentation, but absurdly that page only explains how to declare the class and the inheritance... NOTHING more, so I'm more than lost.

我的目的是把这个code:

My intention is to transform this code:

Public NotInheritable Class MyType

''' <summary>
''' Gets or sets the value.
''' </summary>
''' <value>The value.</value>
Public Property MyProperty As Integer
    Get
        Return Me._MyValue
    End Get
    Set(ByVal value As Integer)

        If value < Me._MyValueMin Then
            If Me._MyValueThrowRangeException Then
                Throw New ArgumentOutOfRangeException("MyValue", Me._MyValueExceptionMessage)
            End If
            Me._MyValue = Me._MyValueMin

        ElseIf value > Me._MyValueMax Then
            If Me._MyValueThrowRangeException Then
                Throw New ArgumentOutOfRangeException("MyValue", Me._MyValueExceptionMessage)
            End If
            Me._MyValue = Me._MyValueMax

        Else
            Me._MyValue = value

        End If

    End Set
End Property
Private _MyValue As Integer = 0I
Private _MyValueMin As Integer = 0I
Private _MyValueMax As Integer = 10I
Private _MyValueThrowRangeException As Boolean = True
Private _MyValueExceptionMessage As String = String.Format("The valid range is beetwen {0} and {1}",
                                                           Me._MyValueMin, Me._MyValueMax)

End Class

到的东西可重用和简化,像这样的:

Into something reusable and simplified, like this:

Public NotInheritable Class MyType

    ''' <summary>
    ''' Gets or sets the value.
    ''' Valid range is between 0 and 10.
    ''' </summary>
    ''' <value>The value.</value>
    <RangeAttribute(0, 10, ThrowRangeException:=False, ExceptionMessage:="")>
    Public Property MyProperty As Integer

End Class

因此​​,要完成这个任务,我已经开始书面方式的属性,但不完全是由于不充分的文档或例子话,我不知道该怎么procceed评价中的二传手,而无需手动添加的getter / setter中的code以上的属性:

So to accomplish this task I've started writting the attribute, but is uncomplete due to an insufficient documentation or examples then I don't know how to procceed to evaluate the values in the setter of a property without adding manually the getter/setter in the property of the code above:

<AttributeUsage(AttributeTargets.Property Or
                AttributeTargets.Parameter Or
                AttributeTargets.ReturnValue Or
                AttributeTargets.Field, 
                AllowMultiple:=False)>
Public Class RangeAttribute : Inherits Attribute

    ''' <summary>
    ''' Indicates the Minimum range value.
    ''' </summary>
    Public Minimum As Single

    ''' <summary>
    ''' Indicates the Maximum range value.
    ''' </summary>
    Public Maximum As Single

    ''' <summary>
    ''' Determines whether to throw an exception when the value is not in range.
    ''' </summary>
    Public ThrowRangeException As Boolean

    ''' <summary>
    ''' Indicates the exception message to show when the value is not in range.
    ''' </summary>
    Public ExceptionMessage As String

    ''' <summary>
    ''' Initializes a new instance of the <see cref="RangeAttribute"/> class.
    ''' </summary>
    ''' <param name="Minimum">The minimum range value.</param>
    ''' <param name="Maximum">The maximum range value.</param>
    Public Sub New(ByVal Minimum As Single,
                   ByVal Maximum As Single)

        Me.New(Minimum, Maximum, ThrowRangeException:=False, ExceptionMessage:=String.Empty)

    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="RangeAttribute"/> class.
    ''' </summary>
    ''' <param name="Minimum">The minimum range value.</param>
    ''' <param name="Maximum">The maximum range value.</param>
    ''' <param name="ThrowRangeException">
    ''' Determines whether to throw an exception when the value is not in range.
    ''' </param>
    Public Sub New(ByVal Minimum As Single,
                   ByVal Maximum As Single,
                   ByVal ThrowRangeException As Boolean,
                   Optional ByVal ExceptionMessage As String = "")

        Me.Minimum = Minimum
        Me.Maximum = Maximum
        Me.ThrowRangeException = ThrowRangeException

        If Not String.IsNullOrEmpty(ExceptionMessage) Then
            Me.ExceptionMessage = ExceptionMessage
        Else
            Me.ExceptionMessage = String.Format("The valid range is beetwen {0} and {1}", Minimum, Maximum)
        End If

    End Sub

End Class

属性code以上会忽略不在范围内的值,我明白这一点,是因为我不想评价什么,但我不知道该怎么做。

The Attribute code above will ignore the values that are not in range, i understand this is because I'm not evaluating nothing, but I don't know how to do it.

推荐答案

那么有可供.Net平台等AOP框架/库, Spring.net AOP KingAOP FluentAOP 再思考,...命名很少。

Well there are other AOP frameworks/libraries available for .Net platform, Spring.net AOP, KingAOP, FluentAOP, Afterthought,... to name a few.

下面是使用建议的解决方案再思考

Here is a proposed solution using Afterthought.

注意:我们可以将AOP框架的基础上用于拦截技术两大类,其中注入在编译时(编译时IL织)拦截code框架和那些在其运行时(运行时IL织造或动态IL-织)做注射。 PostSharp支持在当前版本中这两种方法,每种技术都有自己的优点和缺点,这是出于这个答案的范围,更多信息可以参考的 http://www.postsharp.net/aop.net

NOTE: We can divide AOP frameworks to two major categories based on techniques used for interception, frameworks which inject the interception code during Compile-time (Compile-time IL weaving) and the ones which do the injection during run-time (run-time IL Weaving or Dynamic IL-weaving). PostSharp supports both methods in current version, each technique has its own pros and cons which is out of scope of this answer, for more information you can refer to http://www.postsharp.net/aop.net

在此示例中,我们选择了编译时IL-织造根据再思考框架(再思考只支持编制─时间IL织)

In this sample we chose Compile-time IL-Weaving based on Afterthought framework (Afterthought only supports compile-time IL weaving)

1- prepration

您可以从 https://github.com/r1pper/Afterthought/releases 得到再思考(你可以下载的二进制文件,也可以得到源代码,并自己编译它,我去了二进制途经此地)

you can get Afterthought from https://github.com/r1pper/Afterthought/releases (you can download the binaries or you can get the source and compile it by yourself, I go the binary route here)

解压包有2个文件 Afterthought.dll Afterthought.Amender.exe ,参照 afterthought.dll

extract the package there are 2 files Afterthought.dll and Afterthought.Amender.exe, reference to afterthought.dll.

正如我所说的再思考使用了编译时IL织,这正是 Afterthought.Amender.exe 一样。

As I said before Afterthought uses compile-time IL weaving and this is exactly what Afterthought.Amender.exe does.

我们应该每个版本后调用Amender注入拦截code到我们的组件:

we should call Amender after each build to inject the interception code to our assembly:

Afterthought.Amender.exe集结号

Afterthought.Amender.exe "assembly"

我们可以通过定义自动化任务的新后生成事件为我们的项目(这正是 PostSharp 一样)在这里,我复制再思考夹在我的项目的目录,这是我的后生成事件(可能需要根据你的文件夹位置来改变事件后):

we can automate the task by defining a new Post Build event for our project (this is exactly what PostSharp does) Here I copied Afterthought folder in my project's directory and this is my post build event(you may need to change the post event based on your folder location):

$(PROJECTDIR)再思考​​\ Afterthought.Amender.exe$(TARGETPATH​​)

"$(ProjectDir)Afterthought\Afterthought.Amender.exe" "$(TargetPath)"

好,现在我们准备写我们的code

OK, now we are ready to write our code

2 - 样品code与之间的整数数字范围控制[0,10]

在此示例中,我们定义了一系列的控制属性,并将其命名为 RangeAttribute 的尝试拦截性能setter方法​​来检查我们的设定值的范围之内。

In this sample we define a range control attribute and name it RangeAttribute an try to intercept properties setter method to check if our set value is within the range.

拦截code和注射:

Imports Afterthought
Imports System.Reflection

Public Class RangeAmendment(Of T)
    Inherits Amendment(Of T, T)
    Public Sub New()
        MyBase.New()
        Console.WriteLine("Injecting range check here!")

        Properties.AfterSet(Sub(instance As T, pName As String, pvOld As Object, pv As Object, pvNew As Object)

                                Dim p As PropertyInfo = instance.GetType().GetProperty(pName)
                                Dim att As RangeAttribute = p.GetCustomAttribute(Of RangeAttribute)()
                                If att Is Nothing Then Return

                                Dim v As Object = p.GetValue(instance)
                                Dim castedValue As Integer = Convert.ToInt32(v)
                                If (castedValue < att.Min OrElse castedValue > att.Max) Then
                                    Throw New RangeException(p.Name, att.Min, att.Max)
                                End If

                            End Sub)
    End Sub
End Class

类和定义:

Public Class RangeAttribute
    Inherits Attribute

    Public Property Max As Integer

    Public Property Min As Integer

    Public Sub New(ByVal min As Integer, ByVal max As Integer)
        MyBase.New()
        Me.Min = min
        Me.Max = max
    End Sub
End Class

Public Class RangeException
    Inherits ApplicationException
    Public Sub New(ByVal propertyName As String, ByVal min As Integer, ByVal max As Integer)
        MyBase.New(String.Format("property '{0}' value should be between [{1},{2}]", propertyName, min, max))
    End Sub
End Class



<Amendment(GetType(RangeAmendment(Of )))>
Public Class TestClass
    <Range(0, 10)>
    Public Property Value As Integer

    Public Sub New()
        MyBase.New()
    End Sub
End Class

示例:

Module Module1

        Sub Main()
            Dim test = New TestClass()

            Try
                Console.WriteLine("try setting value to 5")
                test.Value = 5
                Console.WriteLine(test.Value)

                Console.WriteLine("try setting value to 20")
                test.Value = 20
                Console.WriteLine(test.Value)

            Catch ex As RangeException
                Console.WriteLine(ex.Message)
            End Try

            Console.ReadKey()
        End Sub

    End Module

现在,当你建立你的项目,你应该会看到类似的消息在构建输出:

now when you build your project you should see similar message in your build output:

注射范围检查来了!

修宪AopVb3.exe(3.685秒)

Amending AopVb3.exe (3.685 seconds)

==========全部重新生成:1成功,0失败,0跳过==========

========== Rebuild All: 1 succeeded, 0 failed, 0 skipped ==========

和控制台输出应该是:

尝试设置值为5

5

尝试设置值20

属性值值应该在[0,10]

property 'Value' value should be between [0,10]

这篇关于如何创建一个RangeAttribute为WindowsForms?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆