Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redefine GridLength as readonly struct to prevent defensive copies #9905

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -834,9 +834,8 @@ public void UnregisterName(string name) { }
protected virtual void ValidateTemplatedParent(System.Windows.FrameworkElement templatedParent) { }
}
[System.ComponentModel.TypeConverterAttribute(typeof(System.Windows.GridLengthConverter))]
public partial struct GridLength : System.IEquatable<System.Windows.GridLength>
public readonly partial struct GridLength : System.IEquatable<System.Windows.GridLength>
{
private int _dummyPrimitive;
public GridLength(double pixels) { throw null; }
public GridLength(double value, System.Windows.GridUnitType type) { throw null; }
public static System.Windows.GridLength Auto { get { throw null; } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//
//

using MS.Internal;
using System.Windows.Controls;
using System.ComponentModel;
using System.Globalization;

Expand Down Expand Up @@ -40,23 +40,24 @@ public enum GridUnitType
}

/// <summary>
/// GridLength is the type used for various length-like properties in the system,
/// that explicitely support Star unit type. For example, "Width", "Height"
/// properties of ColumnDefinition and RowDefinition used by Grid.
/// <see cref="GridLength"/> is the type used for various length-like properties in the system,
/// that explicitly support <see cref="GridUnitType.Star"/> unit type. For example, "Width", "Height"
/// properties of <see cref="ColumnDefinition"/> and <see cref="RowDefinition"/> used by <see cref="Grid"/>.
/// </summary>
[TypeConverter(typeof(GridLengthConverter))]
public struct GridLength : IEquatable<GridLength>
public readonly struct GridLength : IEquatable<GridLength>
{
//------------------------------------------------------
//
// Constructors
//
//------------------------------------------------------

#region Constructors
/// <summary>
/// Represents the <see cref="Value"/> of this instance; 1.0 if <see cref="Windows.GridUnitType"/> is <see cref="GridUnitType.Auto"/>.
/// </summary>
private readonly double _unitValue;
/// <summary>
/// Represents the <see cref="GridUnitType"/> of this instance.
/// </summary>
private readonly GridUnitType _unitType;

/// <summary>
/// Constructor, initializes the GridLength as absolute value in pixels.
/// Constructor, initializes the <see cref="GridLength"/> as absolute value in pixels.
/// </summary>
/// <param name="pixels">Specifies the number of 'device-independent pixels'
/// (96 pixels-per-inch).</param>
Expand All @@ -65,22 +66,16 @@ public struct GridLength : IEquatable<GridLength>
/// or <c>pixels</c> parameter is <c>double.NegativeInfinity</c>
/// or <c>pixels</c> parameter is <c>double.PositiveInfinity</c>.
/// </exception>
public GridLength(double pixels)
: this(pixels, GridUnitType.Pixel)
{
}
public GridLength(double pixels) : this(pixels, GridUnitType.Pixel) { }

/// <summary>
/// Constructor, initializes the GridLength and specifies what kind of value
/// it will hold.
/// Constructor, initializes the <see cref="GridLength"/> and specifies what kind of value it will hold.
/// </summary>
/// <param name="value">Value to be stored by this GridLength
/// instance.</param>
/// <param name="type">Type of the value to be stored by this GridLength
/// instance.</param>
/// <param name="value">Value to be stored by this <see cref="GridLength"/> instance.</param>
/// <param name="type">Type of the value to be stored by this <see cref="GridLength"/> instance.</param>
/// <remarks>
/// If the <c>type</c> parameter is <c>GridUnitType.Auto</c>,
/// then passed in value is ignored and replaced with <c>0</c>.
/// If the <paramref name="type"/> parameter is <see cref="GridUnitType.Auto"/>,
/// then passed in <paramref name="value"/> is ignored and replaced with 1.0.
/// </remarks>
/// <exception cref="ArgumentException">
/// If <c>value</c> parameter is <c>double.NaN</c>
Expand All @@ -89,166 +84,124 @@ public GridLength(double pixels)
/// </exception>
public GridLength(double value, GridUnitType type)
{
// Check value
if (double.IsNaN(value))
{
throw new ArgumentException(SR.Format(SR.InvalidCtorParameterNoNaN, "value"));
}
if (double.IsInfinity(value))
{
throw new ArgumentException(SR.Format(SR.InvalidCtorParameterNoInfinity, "value"));
}
if ( type != GridUnitType.Auto
&& type != GridUnitType.Pixel
&& type != GridUnitType.Star )
{
throw new ArgumentException(SR.Format(SR.InvalidCtorParameterUnknownGridUnitType, "type"));
}

_unitValue = (type == GridUnitType.Auto) ? 0.0 : value;
throw new ArgumentException(SR.Format(SR.InvalidCtorParameterNoNaN, nameof(value)));
else if (double.IsInfinity(value))
throw new ArgumentException(SR.Format(SR.InvalidCtorParameterNoInfinity, nameof(value)));

// Check unitType
if (type is GridUnitType.Pixel or GridUnitType.Star)
_unitValue = value;
else if (type is GridUnitType.Auto)
_unitValue = 1.0; // Value is ignored in case of "Auto" and defaulted to "1.0"
else
throw new ArgumentException(SR.Format(SR.InvalidCtorParameterUnknownGridUnitType, nameof(type)));

_unitType = type;
}

#endregion Constructors

//------------------------------------------------------
//
// Public Methods
//
//------------------------------------------------------

#region Public Methods

/// <summary>
/// Overloaded operator, compares 2 GridLength's.
/// Compares two <see cref="GridLength"/> structures for equality.
/// </summary>
/// <param name="gl1">first GridLength to compare.</param>
/// <param name="gl2">second GridLength to compare.</param>
/// <returns>true if specified GridLengths have same value
/// and unit type.</returns>
public static bool operator == (GridLength gl1, GridLength gl2)
/// <param name="gl1">The first <see cref="GridLength"/> to compare.</param>
/// <param name="gl2">The second <see cref="GridLength"/> to compare.</param>
/// <returns><see langword="true"/> if specified <see cref="GridLength"/>s have the same
/// <see cref="Value"/> and <see cref="GridUnitType"/> values.</returns>
public static bool operator ==(GridLength gl1, GridLength gl2)
{
return ( gl1.GridUnitType == gl2.GridUnitType
&& gl1.Value == gl2.Value );
return gl1.GridUnitType == gl2.GridUnitType && gl1.Value == gl2.Value;
}

/// <summary>
/// Overloaded operator, compares 2 GridLength's.
/// Compares two<see cref="GridLength"/> structures for inequality.
/// </summary>
/// <param name="gl1">first GridLength to compare.</param>
/// <param name="gl2">second GridLength to compare.</param>
/// <returns>true if specified GridLengths have either different value or
/// unit type.</returns>
public static bool operator != (GridLength gl1, GridLength gl2)
/// <param name="gl1">The first <see cref="GridLength"/> to compare.</param>
/// <param name="gl2">The second <see cref="GridLength"/> to compare.</param>
/// <returns><see langword="true"/> if specified <see cref="GridLength"/>s differ
/// in either <see cref="Value"/> or <see cref="GridUnitType"/>.</returns>
public static bool operator !=(GridLength gl1, GridLength gl2)
{
return ( gl1.GridUnitType != gl2.GridUnitType
|| gl1.Value != gl2.Value );
return !(gl1 == gl2);
}

/// <summary>
/// Compares this instance of GridLength with another object.
/// Compares this instance of <see cref="GridLength"/> with another object.
/// </summary>
/// <param name="oCompare">Reference to an object for comparison.</param>
/// <returns><c>true</c>if this GridLength instance has the same value
/// and unit type as oCompare.</returns>
override public bool Equals(object oCompare)
/// <returns><see langword="true"/> if this <see cref="GridLength"/> instance has the same value
/// and unit type as <paramref name="oCompare"/>, <see langword="false"/> otherwise.</returns>
public override bool Equals(object oCompare)
{
if(oCompare is GridLength)
{
GridLength l = (GridLength)oCompare;
return (this == l);
}
else
return false;
return oCompare is GridLength gridLength && Equals(gridLength);
}

/// <summary>
/// Compares this instance of GridLength with another instance.
/// Compares this instance of <see cref="GridLength"/> with another <see cref="GridLength"/> instance.
/// </summary>
/// <param name="gridLength">Grid length instance to compare.</param>
/// <returns><c>true</c>if this GridLength instance has the same value
/// and unit type as gridLength.</returns>
/// <param name="gridLength">The <see cref="GridLength"/> instance to compare.</param>
/// <returns><see langword="true"/> if this <see cref="GridLength"/> instance has the same value
/// and unit type as <paramref name="gridLength"/>, <see langword="false"/> otherwise.</returns>
public bool Equals(GridLength gridLength)
{
return (this == gridLength);
return this == gridLength;
}

/// <summary>
/// <see cref="Object.GetHashCode"/>
/// Returns the hash code for this <see cref="GridLength"/>.
/// </summary>
/// <returns><see cref="Object.GetHashCode"/></returns>
/// <returns>The hash code for this <see cref="GridLength"/> structure.</returns>
public override int GetHashCode()
{
return ((int)_unitValue + (int)_unitType);
return (int)_unitValue + (int)_unitType;
}

/// <summary>
/// Returns <c>true</c> if this GridLength instance holds
/// an absolute (pixel) value.
/// Returns <see langword="true"/> if this <see cref="GridLength"/> instance holds an absolute (pixel) value.
/// </summary>
public bool IsAbsolute { get { return (_unitType == GridUnitType.Pixel); } }
public bool IsAbsolute { get { return _unitType == GridUnitType.Pixel; } }

/// <summary>
/// Returns <c>true</c> if this GridLength instance is
/// automatic (not specified).
/// Returns <see langword="true"/> if this <see cref="GridLength"/> instance is automatic (not specified).
/// </summary>
public bool IsAuto { get { return (_unitType == GridUnitType.Auto); } }
public bool IsAuto { get { return _unitType == GridUnitType.Auto; } }

/// <summary>
/// Returns <c>true</c> if this GridLength instance holds weighted propertion
/// of available space.
/// Returns <see langword="true"/> if this <see cref="GridLength"/> instance holds weighted propertion of available space.
/// </summary>
public bool IsStar { get { return (_unitType == GridUnitType.Star); } }
public bool IsStar { get { return _unitType == GridUnitType.Star; } }

/// <summary>
/// Returns value part of this GridLength instance.
/// Returns value part of this <see cref="GridLength"/> instance.
/// </summary>
public double Value { get { return ((_unitType == GridUnitType.Auto) ? 1.0 : _unitValue); } }
public double Value { get { return _unitValue; } }

/// <summary>
/// Returns unit type of this GridLength instance.
/// Returns unit type of this <see cref="GridLength"/> instance.
/// </summary>
public GridUnitType GridUnitType { get { return (_unitType); } }
public GridUnitType GridUnitType { get { return _unitType; } }

/// <summary>
/// Returns the string representation of this object.
/// Returns the <see cref="string"/> representation of this <see cref="GridLength"/>.
/// </summary>
/// <returns>A <see cref="string"/> representation of this <see cref="GridLength"/>.</returns>
public override string ToString()
{
return GridLengthConverter.ToString(this, CultureInfo.InvariantCulture);
}

#endregion Public Methods

//------------------------------------------------------
//
// Public Properties
//
//------------------------------------------------------

#region Public Properties

/// <summary>
/// Returns initialized Auto GridLength value.
/// Returns initialized instace of <see cref="GridLength"/> with <see cref="GridUnitType.Auto"/> value.
/// </summary>
public static GridLength Auto
{
get { return (s_auto); }
get { return s_auto; }
}

#endregion Public Properties

//------------------------------------------------------
//
// Private Fields
//
//------------------------------------------------------

#region Private Fields
private double _unitValue; // unit value storage
private GridUnitType _unitType; // unit type storage

// static instance of Auto GridLength
private static readonly GridLength s_auto = new GridLength(1.0, GridUnitType.Auto);
#endregion Private Fields
/// <summary>
/// Pre-initialized instance, used by <see cref="Auto"/> property.
/// </summary>
private static readonly GridLength s_auto = new(1.0, GridUnitType.Auto);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ public void UnregisterName(string name) { }
protected virtual void ValidateTemplatedParent(System.Windows.FrameworkElement templatedParent) { }
}
[System.ComponentModel.TypeConverterAttribute(typeof(System.Windows.GridLengthConverter))]
public partial struct GridLength : System.IEquatable<System.Windows.GridLength>
public readonly partial struct GridLength : System.IEquatable<System.Windows.GridLength>
{
public GridLength(double pixels) { throw null; }
public GridLength(double value, System.Windows.GridUnitType type) { throw null; }
Expand Down