• ASP.NET控件为什么无法使用结构?


    一次在开发一个3D“点”用户Web控件的时候用了结构体,结果碰到了小问题,先给出代码(核心部分):

    [C#]

    namespace CSharp
    {
        namespace CSharp
        {
            /// <summary>
            /// 三维坐标的Struct结构
            /// </summary>
            [TypeConverter(typeof(MyConvertor))]
            public struct DPoint
            {
                private double _x;
                private double _y;
                private double _z;
                [NotifyParentProperty(true)]
                public double Z
                {
                    get { return _z; }
                    set { _z = value; }
                }
                [NotifyParentProperty(true)]
                public double Y
                {
                    get { return _y; }
                    set { _y = value; }
                }
                [NotifyParentProperty(true)]
                public double X
                {
                    get { return _x; }
                    set { _x = value; }
                }
    
                public DPoint(double x, double y, double z)
                {
                    _x = x;
                    _y = y;
                    _z = z;
                }
                public static explicit operator DPoint(string s)
                {
                    string[] values = s.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                    if (values.Length == 3)
                    {
                        double d = Convert.ToDouble(values[0]);
                        double d2 = Convert.ToDouble(values[1]);
                        double d3 = Convert.ToDouble(values[2]);
                        return new DPoint(d, d2, d3);
                    }
                    throw new Exception("输入的维数太多或者太少!");
                }
            }
    
            /// <summary>
            /// 自定义从String转化成DPoint类型 
            /// </summary>
            public class MyConvertor : ExpandableObjectConverter
            {
                /// <summary>
                ///  判断只能string类型作为转换对象,即该标签只加载String上有效
                /// </summary>
                /// <param name="context"></param>
                /// <param name="sourceType"></param>
                /// <returns></returns>
                public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
                {
                    return typeof(string) == sourceType.GetType();
                }
    
                public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
                {
                    return (DPoint)value.ToString();
                }
    
                public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
                {
                    if (value is DPoint)
                    {
                        DPoint dp = (DPoint)value;
                        return string.Format("{0},{1},{2}", dp.X, dp.Y, dp.Z);
                    }
                    throw new Exception("无法转化成标准的String格式!");
                }
                public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
                {
                    return destinationType.GetType() == typeof(string);
                }
    
                public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
                {
                    return new DPoint((double)propertyValues["X"], (double)propertyValues["Y"],(double)propertyValues["Z"]);
                }
             }
            /// <summary>
            /// 三位数组自定义类
            /// </summary>
            [ParseChildren(true), PersistChildren(false)]
            public class MyDPoint : WebControl
            {
                DPoint dp = new DPoint();
    
                [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
                [PersistenceMode(PersistenceMode.InnerProperty)]
                [NotifyParentProperty(true)]
                public DPoint DPoint
                {
                    get
                    {
                        return dp;
                    }
                    set
                    {
                        dp = value;
                    }
                }
    
                protected override void Render(HtmlTextWriter writer)
                {
                    writer.Write(string.Format("[{0},{1},{2}]", DPoint.X, DPoint.Y, DPoint.Z));
                }
            }
        }
    }

    [VB.NET]

    results
    
    .
    
    
     
    
    copy to clipboard | view source | convert again
    
    Namespace CSharp
        Namespace CSharp
            ''' <summary>
            ''' 三维坐标的Struct结构
            ''' </summary>
            <TypeConverter(GetType(MyConvertor))> _
            Public Structure DPoint
                Private _x As Double
                Private _y As Double
                Private _z As Double
                <NotifyParentProperty(True)> _
                Public Property Z() As Double
                    Get
                        Return _z
                    End Get
                    Set
                        _z = value
                    End Set
                End Property
                <NotifyParentProperty(True)> _
                Public Property Y() As Double
                    Get
                        Return _y
                    End Get
                    Set
                        _y = value
                    End Set
                End Property
                <NotifyParentProperty(True)> _
                Public Property X() As Double
                    Get
                        Return _x
                    End Get
                    Set
                        _x = value
                    End Set
                End Property
    
                Public Sub New(x As Double, y As Double, z As Double)
                    _x = x
                    _y = y
                    _z = z
                End Sub
                Public Shared Narrowing Operator CType(s As String) As DPoint
                    Dim values As String() = s.Split(New String() {","}, StringSplitOptions.RemoveEmptyEntries)
                    If values.Length = 3 Then
                        Dim d As Double = Convert.ToDouble(values(0))
                        Dim d2 As Double = Convert.ToDouble(values(1))
                        Dim d3 As Double = Convert.ToDouble(values(2))
                        Return New DPoint(d, d2, d3)
                    End If
                    Throw New Exception("输入的维数太多或者太少!")
                End Operator
            End Structure
    
            ''' <summary>
            ''' 自定义从String转化成DPoint类型 
            ''' </summary>
            Public Class MyConvertor
                Inherits ExpandableObjectConverter
                ''' <summary>
                '''  判断只能string类型作为转换对象,即该标签只加载String上有效
                ''' </summary>
                ''' <param name="context"></param>
                ''' <param name="sourceType"></param>
                ''' <returns></returns>
                Public Overrides Function CanConvertFrom(context As ITypeDescriptorContext, sourceType As Type) As Boolean
                    Return GetType(String) = sourceType.[GetType]()
                End Function
    
                Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, value As Object) As Object
                    Return CType(value.ToString(), DPoint)
                End Function
    
                Public Overrides Function ConvertTo(context As ITypeDescriptorContext, culture As System.Globalization.CultureInfo, value As Object, destinationType As Type) As Object
                    If TypeOf value Is DPoint Then
                        Dim dp As DPoint = CType(value, DPoint)
                        Return String.Format("{0},{1},{2}", dp.X, dp.Y, dp.Z)
                    End If
                    Throw New Exception("无法转化成标准的String格式!")
                End Function
                Public Overrides Function CanConvertTo(context As ITypeDescriptorContext, destinationType As Type) As Boolean
                    Return destinationType.[GetType]() = GetType(String)
                End Function
    
                Public Overrides Function CreateInstance(context As ITypeDescriptorContext, propertyValues As System.Collections.IDictionary) As Object
                    Return New DPoint(CDbl(propertyValues("X")), CDbl(propertyValues("Y")), CDbl(propertyValues("Z")))
                End Function
            End Class
            ''' <summary>
            ''' 三位数组自定义类
            ''' </summary>
            <ParseChildren(True), PersistChildren(False)> _
            Public Class MyDPoint
                Inherits WebControl
                Private dp As New DPoint()
    
                <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)> _
                <PersistenceMode(PersistenceMode.InnerProperty)> _
                <NotifyParentProperty(True)> _
                Public Property DPoint() As DPoint
                    Get
                        Return dp
                    End Get
                    Set
                        dp = value
                    End Set
                End Property
    
                Protected Overrides Sub Render(writer As HtmlTextWriter)
                    writer.Write(String.Format("[{0},{1},{2}]", DPoint.X, DPoint.Y, DPoint.Z))
                End Sub
            End Class
        End Namespace
    End Namespace

    编译整个程序之后直接从工具栏把该控件拖拽到页面上,一切OK;随后接着在设计器(属性面板)中修改X,Y,Z的内容——悲剧发生了!

    这是为啥?Why?不知道哎……不能用结构?结构没有序列化?结构的构造函数默认是无参的,结构体没初始化一次就丢弃原来的那个……?种种胡乱猜测萦绕在我心头……乱乱乱,烦烦烦!

    正当我绝望之际,无疑习惯性地在自定义的MyConvertor中敲入“public override”一行字符时候,一个东西映入我眼帘:

    去查询MSDN文档,发现该方法是虚方法,作用是“返回此对象是否支持可以从列表中选取的标准值集”。重写它设置成true就可以啦!

    现在思考以下——为什么Class不需要重写它(默认返回false)也可以,但是struct就一定需要呢?

    【分析】

    如果你使用结构,那么编译之后aspx代码是这个样子:

    <cc1:MyDPoint runat="server" DPoint-X="5" DPoint-Y="5" DPoint-Z="5"></cc2:MyDPoint>

    这个代码实质类似:
    [C#]

    MyDPoint.DPoint.X = 5;

    [VB.NET]

    MyDPoint.DPoint.X = 5

    但是这个请注意:因为DPoint是MyDPoint的一个属性(是结构类型!),因此这意味着你无法改变MyDPoint.DPoint真实值(你可以想想,如果MyDPoint.DPoint赋值给其它DPoint,并且视图改变X,Y或者是Z的数值,结果是无法影响到MyDPoint.DPoint的)。
    值得注意的是——VS的编译器也是无法通过以上语句的编译的。

  • 相关阅读:
    Python3笔记029
    Python3笔记028
    Python3笔记027
    Python3笔记026
    Python3笔记025
    Python3笔记024
    find the oracle logs
    asm command
    网上看到的一个朋友写的不错收藏着.
    在IBM AIX上安装Oracle RAC ,很多人都在找的东东.....
  • 原文地址:https://www.cnblogs.com/ServiceboyNew/p/2782219.html
Copyright © 2020-2023  润新知