Files
PowerShell/src/System.Management.Automation/engine/MshMemberInfo.cs
T

4819 lines
174 KiB
C#
Raw Normal View History

/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Linq;
using System.Management.Automation.Language;
using System.Reflection;
using System.Globalization;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections;
using System.ComponentModel;
using System.Text;
using System.Management.Automation.Internal;
using Microsoft.PowerShell;
using TypeTable = System.Management.Automation.Runspaces.TypeTable;
#pragma warning disable 1634, 1691 // Stops compiler from warning about unknown warnings
#pragma warning disable 56503
namespace System.Management.Automation
{
#region PSMemberInfo
/// <summary>
/// Enumerates all possible types of members
/// </summary>
[TypeConverterAttribute(typeof(LanguagePrimitives.EnumMultipleTypeConverter))]
[FlagsAttribute()]
public enum PSMemberTypes
{
/// <summary>
/// An alias to another member
/// </summary>
AliasProperty = 1,
/// <summary>
/// A property defined as a reference to a method
/// </summary>
CodeProperty = 2,
/// <summary>
/// A property from the BaseObject
/// </summary>
Property = 4,
/// <summary>
/// A prorperty defined by a Name-Value pair
/// </summary>
NoteProperty = 8,
/// <summary>
/// A property defined by script language
/// </summary>
ScriptProperty = 16,
/// <summary>
/// A set of properties
/// </summary>
PropertySet = 32,
/// <summary>
/// A method from the BaseObject
/// </summary>
Method = 64,
/// <summary>
/// A method defined as a reference to another method
/// </summary>
CodeMethod = 128,
/// <summary>
/// A method defined as a script
/// </summary>
ScriptMethod = 256,
/// <summary>
/// A member that acts like a Property that takes parameters. This is not consider to be a property or a method.
/// </summary>
ParameterizedProperty = 512,
/// <summary>
/// A set of members
/// </summary>
MemberSet = 1024,
/// <summary>
/// All events
/// </summary>
Event = 2048,
/// <summary>
/// All dynamic members (where PowerShell cannot know the type of the member)
/// </summary>
Dynamic = 4096,
/// <summary>
/// All property member types
/// </summary>
Properties = AliasProperty | CodeProperty | Property | NoteProperty | ScriptProperty,
/// <summary>
/// All method member types
/// </summary>
Methods = CodeMethod | Method | ScriptMethod,
/// <summary>
/// All member types
/// </summary>
All = Properties | Methods | Event | PropertySet | MemberSet | ParameterizedProperty | Dynamic
}
/// <summary>
/// Enumerator for all possible views available on a PSObject.
/// </summary>
[TypeConverterAttribute(typeof(LanguagePrimitives.EnumMultipleTypeConverter))]
[FlagsAttribute()]
public enum PSMemberViewTypes
{
/// <summary>
/// Extended methods / properties
/// </summary>
Extended = 1,
/// <summary>
/// Adapted methods / properties
/// </summary>
Adapted = 2,
/// <summary>
/// Base methods / properties
/// </summary>
Base = 4,
/// <summary>
/// All methods / properties
/// </summary>
All = Extended | Adapted | Base
}
/// <summary>
/// Match options
/// </summary>
[FlagsAttribute]
internal enum MshMemberMatchOptions
{
/// <summary>
/// No options
/// </summary>
None = 0,
/// <summary>
/// Hidden members should be displayed
/// </summary>
IncludeHidden = 1,
/// <summary>
/// Only include members with <see cref="PSMemberInfo.ShouldSerialize"/> property set to <c>true</c>
/// </summary>
OnlySerializable = 2
}
/// <summary>
/// Serves as the base class for all members of an PSObject
/// </summary>
public abstract class PSMemberInfo
{
internal object instance;
internal string name;
internal bool ShouldSerialize { get; set; }
internal virtual void ReplicateInstance(object particularInstance)
{
this.instance = particularInstance;
}
internal void SetValueNoConversion(object setValue)
{
PSProperty thisAsProperty = this as PSProperty;
if (thisAsProperty == null)
{
this.Value = setValue;
return;
}
thisAsProperty.SetAdaptedValue(setValue, false);
}
/// <summary>
/// Initializes a new instance of an PSMemberInfo derived class
/// </summary>
protected PSMemberInfo()
{
ShouldSerialize = true;
IsInstance = true;
}
internal void CloneBaseProperties(PSMemberInfo destiny)
{
destiny.name = name;
destiny.IsHidden = IsHidden;
destiny.IsReservedMember = IsReservedMember;
destiny.IsInstance = IsInstance;
destiny.instance = instance;
destiny.ShouldSerialize = ShouldSerialize;
}
/// <summary>
/// Gets the member type
/// </summary>
public abstract PSMemberTypes MemberType { get; }
/// <summary>
/// Gets the member name
/// </summary>
public string Name
{
get
{
return this.name;
}
}
/// <summary>
/// Allows a derived class to set the member name...
/// </summary>
/// <param name="name"></param>
protected void SetMemberName(string name)
{
if (string.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
}
/// <summary>
/// True if this is one of the reserved members
/// </summary>
internal bool IsReservedMember { get; set; }
/// <summary>
/// True if the member should be hidden when searching with PSMemberInfoInternalCollection's Match
/// or enumerating a collection.
/// This should not be settable as it would make the count of hidden properties in
/// PSMemberInfoInternalCollection invalid.
/// For now, we are carefully setting this.isHidden before adding
/// the members toPSObjectMembersetCollection. In the future, we might need overload for all
/// PSMemberInfo constructors to take isHidden.
/// </summary>
internal bool IsHidden { get; set; }
/// <summary>
/// True if this member has been added to the instance as opposed to
/// coming from the adapter or from type data
/// </summary>
public bool IsInstance { get; internal set; }
/// <summary>
/// Gets and Sets the value of this member
/// </summary>
/// <exception cref="GetValueException">When getting the value of a property throws an exception.
/// This exception is also thrown if the property is an <see cref="PSScriptProperty"/> and there
/// is no Runspace to run the script.</exception>
/// <exception cref="SetValueException">When setting the value of a property throws an exception.
/// This exception is also thrown if the property is an <see cref="PSScriptProperty"/> and there
/// is no Runspace to run the script.</exception>
/// <exception cref="ExtendedTypeSystemException">When some problem other then getting/setting the value happened</exception>
public abstract object Value { get; set; }
/// <summary>
/// Gets the type of the value for this member
/// </summary>
/// <exception cref="ExtendedTypeSystemException">When there was a problem getting the property</exception>
public abstract string TypeNameOfValue { get; }
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public abstract PSMemberInfo Copy();
internal bool MatchesOptions(MshMemberMatchOptions options)
{
if (this.IsHidden && (0 == (options & MshMemberMatchOptions.IncludeHidden)))
{
return false;
}
if (!this.ShouldSerialize && (0 != (options & MshMemberMatchOptions.OnlySerializable)))
{
return false;
}
return true;
}
}
/// <summary>
/// Serves as a base class for all members that behave like properties.
/// </summary>
public abstract class PSPropertyInfo : PSMemberInfo
{
/// <summary>
/// Initializes a new instance of an PSPropertyInfo derived class
/// </summary>
protected PSPropertyInfo() { }
/// <summary>
/// Gets true if this property can be set
/// </summary>
2016-07-29 13:02:49 -07:00
public abstract bool IsSettable { get; }
/// <summary>
/// Gets true if this property can be read
/// </summary>
2016-07-29 13:02:49 -07:00
public abstract bool IsGettable { get; }
internal Exception NewSetValueException(Exception e, string errorId)
{
return new SetValueInvocationException(errorId,
e,
ExtendedTypeSystem.ExceptionWhenSetting,
this.Name, e.Message);
}
internal Exception NewGetValueException(Exception e, string errorId)
{
return new GetValueInvocationException(errorId,
e,
ExtendedTypeSystem.ExceptionWhenGetting,
this.Name, e.Message);
}
}
/// <summary>
/// Serves as an alias to another member
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSAliasProperty"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSAliasProperty : PSPropertyInfo
{
/// <summary>
/// Returns the string representation of this property
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.Name);
returnValue.Append(" = ");
2016-08-02 13:29:09 -07:00
if (ConversionType != null)
{
returnValue.Append("(");
2016-08-02 13:29:09 -07:00
returnValue.Append(ConversionType);
returnValue.Append(")");
}
2016-08-02 13:29:09 -07:00
returnValue.Append(ReferencedMemberName);
return returnValue.ToString();
}
/// <summary>
/// Initializes a new instance of PSAliasProperty setting the name of the alias
/// and the name of the member this alias refers to.
/// </summary>
/// <param name="name">name of the alias</param>
/// <param name="referencedMemberName">name of the member this alias refers to</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSAliasProperty(string name, string referencedMemberName)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (String.IsNullOrEmpty(referencedMemberName))
{
throw PSTraceSource.NewArgumentException("referencedMemberName");
}
2016-08-02 13:29:09 -07:00
ReferencedMemberName = referencedMemberName;
}
/// <summary>
/// Initializes a new instance of PSAliasProperty setting the name of the alias,
/// the name of the member this alias refers to and the type to convert the referenced
/// member's value.
/// </summary>
/// <param name="name">name of the alias</param>
/// <param name="referencedMemberName">name of the member this alias refers to</param>
/// <param name="conversionType">the type to convert the referenced member's value</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSAliasProperty(string name, string referencedMemberName, Type conversionType)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (String.IsNullOrEmpty(referencedMemberName))
{
throw PSTraceSource.NewArgumentException("referencedMemberName");
}
2016-08-02 13:29:09 -07:00
ReferencedMemberName = referencedMemberName;
// conversionType is optional and can be null
2016-08-02 13:29:09 -07:00
ConversionType = conversionType;
}
/// <summary>
/// Gets the name of the member this alias refers to
/// </summary>
2016-08-02 13:29:09 -07:00
public string ReferencedMemberName { get; }
/// <summary>
/// Gets the member this alias refers to
/// </summary>
internal PSMemberInfo ReferencedMember
{
get
{
2016-08-02 13:29:09 -07:00
return this.LookupMember(ReferencedMemberName);
}
}
/// <summary>
/// Gets the the type to convert the referenced member's value. It might be
/// null when no conversion is done.
/// </summary>
2016-08-02 13:29:09 -07:00
public Type ConversionType { get; private set; }
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
2016-08-02 13:29:09 -07:00
PSAliasProperty alias = new PSAliasProperty(name, ReferencedMemberName);
alias.ConversionType = ConversionType;
CloneBaseProperties(alias);
return alias;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.AliasProperty;
}
}
/// <summary>
/// Gets the type of the value for this member
/// </summary>
/// <exception cref="ExtendedTypeSystemException">
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not present
/// </exception>
public override string TypeNameOfValue
{
get
{
2016-08-02 13:29:09 -07:00
if (ConversionType != null)
{
2016-08-02 13:29:09 -07:00
return ConversionType.FullName;
}
return this.ReferencedMember.TypeNameOfValue;
}
}
/// <summary>
/// Gets true if this property can be set
/// </summary>
/// <exception cref="ExtendedTypeSystemException">
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not presen
/// </exception>
public override bool IsSettable
{
get
{
PSPropertyInfo memberProperty = this.ReferencedMember as PSPropertyInfo;
if (memberProperty != null)
{
return memberProperty.IsSettable;
}
return false;
}
}
/// <summary>
/// Gets true if this property can be read
/// </summary>
/// <exception cref="ExtendedTypeSystemException">
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not present
/// </exception>
public override bool IsGettable
{
get
{
PSPropertyInfo memberProperty = this.ReferencedMember as PSPropertyInfo;
if (memberProperty != null)
{
return memberProperty.IsGettable;
}
return false;
}
}
private PSMemberInfo LookupMember(string name)
{
bool hasCycle;
PSMemberInfo returnValue;
LookupMember(name, new HashSet<string>(StringComparer.OrdinalIgnoreCase), out returnValue, out hasCycle);
if (hasCycle)
{
2016-07-29 13:02:49 -07:00
throw new
ExtendedTypeSystemException(
2016-07-29 13:02:49 -07:00
"CycleInAliasLookup",
null,
ExtendedTypeSystem.CycleInAlias,
this.Name);
}
return returnValue;
}
private void LookupMember(string name, HashSet<string> visitedAliases, out PSMemberInfo returnedMember, out bool hasCycle)
{
returnedMember = null;
if (this.instance == null)
{
throw new ExtendedTypeSystemException("AliasLookupMemberOutsidePSObject",
null,
ExtendedTypeSystem.AccessMemberOutsidePSObject,
name);
}
PSMemberInfo member = PSObject.AsPSObject(this.instance).Properties[name];
if (member == null)
{
throw new ExtendedTypeSystemException(
2016-07-29 13:02:49 -07:00
"AliasLookupMemberNotPresent",
null,
ExtendedTypeSystem.MemberNotPresent,
name);
}
PSAliasProperty aliasMember = member as PSAliasProperty;
if (aliasMember == null)
{
hasCycle = false;
returnedMember = member;
return;
}
if (visitedAliases.Contains(name))
{
hasCycle = true;
return;
}
visitedAliases.Add(name);
LookupMember(aliasMember.ReferencedMemberName, visitedAliases, out returnedMember, out hasCycle);
}
/// <summary>
/// Gets and Sets the value of this member
/// </summary>
/// <exception cref="ExtendedTypeSystemException">
/// When
/// the alias has not been added to an PSObject or
/// the alias has a cycle or
/// an aliased member is not present
/// </exception>
/// <exception cref="GetValueException">When getting the value of a property throws an exception</exception>
/// <exception cref="SetValueException">When setting the value of a property throws an exception</exception>
public override object Value
{
get
{
object returnValue = this.ReferencedMember.Value;
2016-08-02 13:29:09 -07:00
if (ConversionType != null)
{
2016-08-02 13:29:09 -07:00
returnValue = LanguagePrimitives.ConvertTo(returnValue, ConversionType, CultureInfo.InvariantCulture);
}
return returnValue;
}
set
{
this.ReferencedMember.Value = value;
}
}
#endregion virtual implementation
}
/// <summary>
/// Serves as a property implemented with references to methods for getter and setter.
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSCodeProperty"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSCodeProperty : PSPropertyInfo
{
/// <summary>
/// Returns the string representation of this property
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.TypeNameOfValue);
returnValue.Append(" ");
returnValue.Append(this.Name);
returnValue.Append("{");
if (this.IsGettable)
{
returnValue.Append("get=");
2016-08-02 13:29:09 -07:00
returnValue.Append(GetterCodeReference.Name);
returnValue.Append(";");
}
if (this.IsSettable)
{
returnValue.Append("set=");
2016-08-02 13:29:09 -07:00
returnValue.Append(SetterCodeReference.Name);
returnValue.Append(";");
}
returnValue.Append("}");
return returnValue.ToString();
}
/// <summary>
/// Called from TypeTableUpdate before SetSetterFromTypeTable is called
/// </summary>
internal void SetGetterFromTypeTable(Type type, string methodName)
{
MethodInfo methodAsMember = null;
try
{
methodAsMember = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
}
catch (AmbiguousMatchException)
{
// Ignore the AmbiguousMatchException.
// We will generate error below if we cannot find exactly one match method.
}
2016-07-29 13:02:49 -07:00
if (methodAsMember == null)
{
throw new ExtendedTypeSystemException(
"GetterFormatFromTypeTable",
null,
ExtendedTypeSystem.CodePropertyGetterFormat);
}
SetGetter(methodAsMember);
}
/// <summary>
/// Called from TypeTableUpdate after SetGetterFromTypeTable is called
/// </summary>
internal void SetSetterFromTypeTable(Type type, string methodName)
{
MethodInfo methodAsMember = null;
try
{
methodAsMember = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
}
catch (AmbiguousMatchException)
{
// Ignore the AmbiguousMatchException.
// We will generate error below if we cannot find exactly one match method.
}
if (methodAsMember == null)
{
throw new ExtendedTypeSystemException(
"SetterFormatFromTypeTable",
null,
ExtendedTypeSystem.CodePropertySetterFormat);
}
2016-08-02 13:29:09 -07:00
SetSetter(methodAsMember, GetterCodeReference);
}
/// <summary>
/// Used from TypeTable with the internal constructor
/// </summary>
internal void SetGetter(MethodInfo methodForGet)
{
if (methodForGet == null)
{
2016-08-02 13:29:09 -07:00
GetterCodeReference = null;
return;
}
if (!CheckGetterMethodInfo(methodForGet))
{
throw new ExtendedTypeSystemException(
"GetterFormat",
null,
ExtendedTypeSystem.CodePropertyGetterFormat);
}
2016-08-02 13:29:09 -07:00
GetterCodeReference = methodForGet;
}
internal static bool CheckGetterMethodInfo(MethodInfo methodForGet)
{
ParameterInfo[] parameters = methodForGet.GetParameters();
return methodForGet.IsPublic
&& methodForGet.IsStatic
&& methodForGet.ReturnType != typeof(void)
&& parameters.Length == 1
&& parameters[0].ParameterType == typeof(PSObject);
}
/// <summary>
/// Used from TypeTable with the internal constructor
/// </summary>
private void SetSetter(MethodInfo methodForSet, MethodInfo methodForGet)
{
if (methodForSet == null)
{
if (methodForGet == null)
{
throw new ExtendedTypeSystemException(
"SetterAndGetterNullFormat",
null,
ExtendedTypeSystem.CodePropertyGetterAndSetterNull);
}
2016-08-02 13:29:09 -07:00
SetterCodeReference = null;
return;
}
if (!CheckSetterMethodInfo(methodForSet, methodForGet))
{
throw new ExtendedTypeSystemException(
"SetterFormat",
null,
ExtendedTypeSystem.CodePropertySetterFormat);
}
2016-08-02 13:29:09 -07:00
SetterCodeReference = methodForSet;
}
internal static bool CheckSetterMethodInfo(MethodInfo methodForSet, MethodInfo methodForGet)
{
ParameterInfo[] parameters = methodForSet.GetParameters();
return methodForSet.IsPublic
&& methodForSet.IsStatic
&& methodForSet.ReturnType == typeof(void)
&& parameters.Length == 2
&& parameters[0].ParameterType == typeof(PSObject)
&& (methodForGet == null || methodForGet.ReturnType == parameters[1].ParameterType);
}
/// <summary>
/// Used from TypeTable to delay setting getter and setter
/// </summary>
internal PSCodeProperty(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
}
/// <summary>
/// Initializes a new instance of the PSCodeProperty class as a read only property.
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="getterCodeReference">This should be a public static non void method taking one PSObject parameter.</param>
/// <exception cref="ArgumentException">if namme is null or empty or getterCodeReference is null</exception>
/// <exception cref="ExtendedTypeSystemException">if getterCodeReference doesn't have the right format.</exception>
public PSCodeProperty(string name, MethodInfo getterCodeReference)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterCodeReference == null)
{
throw PSTraceSource.NewArgumentNullException("getterCodeReference");
}
SetGetter(getterCodeReference);
}
/// <summary>
/// Initializes a new instance of the PSCodeProperty class. Setter or getter can be null, but both cannot be null.
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="getterCodeReference">This should be a public static non void method taking one PSObject parameter.</param>
/// <param name="setterCodeReference">This should be a public static void method taking 2 parameters, where the first is an PSObject.</param>
/// <exception cref="ArgumentException">when methodForGet and methodForSet are null</exception>
/// <exception cref="ExtendedTypeSystemException">
/// if:
/// - getterCodeReference doesn't have the right format,
/// - setterCodeReference doesn't have the right format,
/// - both getterCodeReference and setterCodeReference are null.
/// </exception>
public PSCodeProperty(string name, MethodInfo getterCodeReference, MethodInfo setterCodeReference)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterCodeReference == null && setterCodeReference == null)
{
throw PSTraceSource.NewArgumentNullException("getterCodeReference setterCodeReference");
}
SetGetter(getterCodeReference);
SetSetter(setterCodeReference, getterCodeReference);
}
/// <summary>
/// Gets the method used for the properties' getter. It might be null.
/// </summary>
2016-08-02 13:29:09 -07:00
public MethodInfo GetterCodeReference { get; private set; }
/// <summary>
/// Gets the method used for the properties' setter. It might be null.
/// </summary>
2016-08-02 13:29:09 -07:00
public MethodInfo SetterCodeReference { get; private set; }
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
2016-08-02 13:29:09 -07:00
PSCodeProperty property = new PSCodeProperty(name, GetterCodeReference, SetterCodeReference);
CloneBaseProperties(property);
return property;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.CodeProperty;
}
}
/// <summary>
/// Gets true if this property can be set
/// </summary>
public override bool IsSettable
{
get
{
return this.SetterCodeReference != null;
}
}
/// <summary>
/// Gets true if this property can be read
/// </summary>
public override bool IsGettable
{
get
{
2016-08-02 13:29:09 -07:00
return GetterCodeReference != null;
}
}
/// <summary>
/// Gets and Sets the value of this member
/// </summary>
/// <exception cref="GetValueException">When getting and there is no getter or when the getter throws an exception</exception>
/// <exception cref="SetValueException">When setting and there is no setter or when the setter throws an exception</exception>
public override object Value
{
get
{
2016-08-02 13:29:09 -07:00
if (GetterCodeReference == null)
{
throw new GetValueException("GetWithoutGetterFromCodePropertyValue",
null,
ExtendedTypeSystem.GetWithoutGetterException,
this.Name);
}
try
{
2016-08-02 13:29:09 -07:00
return GetterCodeReference.Invoke(null, new object[1] { this.instance });
}
catch (TargetInvocationException ex)
{
Exception inner = (ex.InnerException == null) ? ex : ex.InnerException;
throw new GetValueInvocationException("CatchFromCodePropertyGetTI",
inner,
ExtendedTypeSystem.ExceptionWhenGetting,
this.name, inner.Message);
}
catch (Exception e)
{
if (e is GetValueException)
{
throw;
}
CommandProcessorBase.CheckForSevereException(e);
throw new GetValueInvocationException("CatchFromCodePropertyGet",
e,
ExtendedTypeSystem.ExceptionWhenGetting,
this.name, e.Message);
}
}
set
{
2016-08-02 13:29:09 -07:00
if (SetterCodeReference == null)
{
throw new SetValueException("SetWithoutSetterFromCodeProperty",
null,
ExtendedTypeSystem.SetWithoutSetterException,
this.Name);
}
try
{
2016-08-02 13:29:09 -07:00
SetterCodeReference.Invoke(null, new object[2] { this.instance, value });
}
catch (TargetInvocationException ex)
{
Exception inner = (ex.InnerException == null) ? ex : ex.InnerException;
throw new SetValueInvocationException("CatchFromCodePropertySetTI",
inner,
ExtendedTypeSystem.ExceptionWhenSetting,
this.name, inner.Message);
}
catch (Exception e)
{
if (e is SetValueException)
{
throw;
}
CommandProcessorBase.CheckForSevereException(e);
throw new SetValueInvocationException("CatchFromCodePropertySet",
e,
ExtendedTypeSystem.ExceptionWhenSetting,
this.name, e.Message);
}
}
}
/// <summary>
/// Gets the type of the value for this member
/// </summary>
/// <exception cref="GetValueException">If there is no property getter</exception>
public override string TypeNameOfValue
{
get
{
2016-08-02 13:29:09 -07:00
if (GetterCodeReference == null)
{
throw new GetValueException("GetWithoutGetterFromCodePropertyTypeOfValue",
null,
ExtendedTypeSystem.GetWithoutGetterException,
this.Name);
}
2016-08-02 13:29:09 -07:00
return GetterCodeReference.ReturnType.FullName;
}
}
#endregion virtual implementation
}
/// <summary>
/// Used to access the adapted or base properties from the BaseObject
/// </summary>
public class PSProperty : PSPropertyInfo
{
/// <summary>
/// Returns the string representation of this property
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
if (this.isDeserialized)
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.TypeNameOfValue);
returnValue.Append(" {get;set;}");
return returnValue.ToString();
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyToString(this);
}
/// <summary>
/// used by the adapters to keep intermediate data used between DoGetProperty and
/// DoGetValue or DoSetValue
/// </summary>
internal string typeOfValue;
internal object serializedValue;
internal bool isDeserialized;
/// <summary>
/// This will be either instance.adapter or instance.clrAdapter
/// </summary>
internal Adapter adapter;
internal object adapterData;
internal object baseObject;
/// <summary>
/// Constructs a property from a serialized value
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="serializedValue">value of the property</param>
internal PSProperty(string name, object serializedValue)
{
this.isDeserialized = true;
this.serializedValue = serializedValue;
this.name = name;
}
/// <summary>
/// Constructs this proprerty
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="adapter">adapter used in DoGetProperty</param>
/// <param name="baseObject">object passed to DoGetProperty</param>
/// <param name="adapterData">adapter specific data</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal PSProperty(string name, Adapter adapter, object baseObject, object adapterData)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
this.adapter = adapter;
this.adapterData = adapterData;
this.baseObject = baseObject;
}
2016-07-29 13:02:49 -07:00
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
PSProperty property = new PSProperty(this.name, this.adapter, this.baseObject, this.adapterData);
CloneBaseProperties(property);
property.typeOfValue = this.typeOfValue;
property.serializedValue = this.serializedValue;
property.isDeserialized = this.isDeserialized;
return property;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.Property;
}
}
private object GetAdaptedValue()
{
if (this.isDeserialized)
{
return serializedValue;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
object o = adapter.BasePropertyGet(this);
return o;
}
internal void SetAdaptedValue(object setValue, bool shouldConvert)
{
if (this.isDeserialized)
{
serializedValue = setValue;
return;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
adapter.BasePropertySet(this, setValue, shouldConvert);
}
/// <summary>
/// Gets or sets the value of this property
/// </summary>
/// <exception cref="GetValueException">When getting the value of a property throws an exception</exception>
/// <exception cref="SetValueException">When setting the value of a property throws an exception</exception>
public override object Value
{
get
{
return GetAdaptedValue();
}
set
{
SetAdaptedValue(value, true);
}
}
/// <summary>
/// Gets true if this property can be set
/// </summary>
public override bool IsSettable
{
get
{
if (this.isDeserialized)
{
return true;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyIsSettable(this);
}
}
/// <summary>
/// Gets true if this property can be read
/// </summary>
public override bool IsGettable
{
get
{
if (this.isDeserialized)
{
return true;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyIsGettable(this);
}
}
/// <summary>
/// Gets the type of the value for this member
/// </summary>
public override string TypeNameOfValue
{
get
{
if (this.isDeserialized)
{
if (serializedValue == null)
{
return String.Empty;
}
PSObject serializedValueAsPSObject = serializedValue as PSObject;
if (serializedValueAsPSObject != null)
{
var typeNames = serializedValueAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
// type name at 0-th index is the most specific type (i.e. deserialized.system.io.directoryinfo)
// type names at other indices are less specific (i.e. deserialized.system.object)
return typeNames[0];
}
}
return serializedValue.GetType().FullName;
}
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null), "if it is deserialized, it should have all these properties set");
return adapter.BasePropertyType(this);
}
}
#endregion virtual implementation
}
/// <summary>
/// A property created by a user-defined PSPropertyAdapter
/// </summary>
public class PSAdaptedProperty : PSProperty
{
/// <summary>
/// Creates a property for the given base object
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="tag">an adapter can use this object to keep any arbitrary data it needs</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSAdaptedProperty(string name, object tag)
: base(name, null, null, tag)
{
//
// Note that the constructor sets the adapter and base object to null; the ThirdPartyAdapter managing this property must set these values
//
}
internal PSAdaptedProperty(string name, Adapter adapter, object baseObject, object adapterData)
: base(name, adapter, baseObject, adapterData)
{
}
/// <summary>
/// Copy an adapted property.
/// </summary>
public override PSMemberInfo Copy()
{
PSAdaptedProperty property = new PSAdaptedProperty(this.name, this.adapter, this.baseObject, this.adapterData);
CloneBaseProperties(property);
property.typeOfValue = this.typeOfValue;
property.serializedValue = this.serializedValue;
property.isDeserialized = this.isDeserialized;
return property;
}
/// <summary>
/// Gets the object the property belongs to
/// </summary>
public object BaseObject
{
get
{
return this.baseObject;
}
}
/// <summary>
/// Gets the data attached to this property
/// </summary>
public object Tag
{
get
{
return this.adapterData;
}
}
}
/// <summary>
/// Serves as a property that is a simple name-value pair.
/// </summary>
public class PSNoteProperty : PSPropertyInfo
{
/// <summary>
/// Returns the string representation of this property
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(GetDisplayTypeNameOfValue(this.Value));
returnValue.Append(" ");
returnValue.Append(this.Name);
returnValue.Append("=");
returnValue.Append(this.noteValue == null ? "null" : this.noteValue.ToString());
return returnValue.ToString();
}
internal object noteValue;
/// <summary>
/// Initiializes a new instance of the PSNoteProperty class.
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="value">value of the property</param>
/// <exception cref="ArgumentException">for an empty or null name</exception>
public PSNoteProperty(string name, object value)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
// value can be null
this.noteValue = value;
}
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
PSNoteProperty property = new PSNoteProperty(this.name, this.noteValue);
CloneBaseProperties(property);
return property;
}
/// <summary>
/// Gets PSMemberTypes.NoteProperty
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.NoteProperty;
}
}
/// <summary>
/// Gets true since the value of an PSNoteProperty can always be set
/// </summary>
public override bool IsSettable
{
get
{
return this.IsInstance;
}
}
/// <summary>
/// Gets true since the value of an PSNoteProperty can always be obtained
/// </summary>
public override bool IsGettable
{
get
{
return true;
}
}
/// <summary>
/// Gets or sets the value of this property
/// </summary>
public override object Value
{
get
{
return this.noteValue;
}
set
{
if (!this.IsInstance)
{
throw new SetValueException("ChangeValueOfStaticNote",
null,
ExtendedTypeSystem.ChangeStaticMember,
this.Name);
}
this.noteValue = value;
}
}
/// <summary>
/// Gets the type of the value for this member
/// </summary>
public override string TypeNameOfValue
{
get
{
object val = this.Value;
if (val == null)
{
return typeof(object).FullName;
}
PSObject valAsPSObject = val as PSObject;
if (valAsPSObject != null)
{
var typeNames = valAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
// type name at 0-th index is the most specific type (i.e. system.string)
// type names at other indices are less specific (i.e. system.object)
return typeNames[0];
}
}
return val.GetType().FullName;
}
}
#endregion virtual implementation
internal static string GetDisplayTypeNameOfValue(object val)
{
string displayTypeName = null;
PSObject valAsPSObject = val as PSObject;
if (valAsPSObject != null)
{
var typeNames = valAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
displayTypeName = typeNames[0];
}
}
if (string.IsNullOrEmpty(displayTypeName))
{
2016-07-29 13:02:49 -07:00
displayTypeName = val == null
? "object"
: ToStringCodeMethods.Type(val.GetType(), dropNamespaces: true);
}
return displayTypeName;
}
}
/// <summary>
/// Serves as a property that is a simple name-value pair.
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSNoteProperty"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSVariableProperty : PSNoteProperty
{
/// <summary>
/// Returns the string representation of this property
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(GetDisplayTypeNameOfValue(_variable.Value));
returnValue.Append(" ");
returnValue.Append(_variable.Name);
returnValue.Append("=");
returnValue.Append(_variable.Value ?? "null");
return returnValue.ToString();
}
internal PSVariable _variable;
/// <summary>
/// Initiializes a new instance of the PSVariableProperty class. This is
/// a subclass of the NoteProperty that wraps a variable instead of a simple value.
/// </summary>
/// <param name="variable">The variable to wrap</param>
/// <exception cref="ArgumentException">for an empty or null name</exception>
public PSVariableProperty(PSVariable variable)
2016-07-29 13:02:49 -07:00
: base(variable != null ? variable.Name : null, null)
{
if (variable == null)
{
throw PSTraceSource.NewArgumentException("variable");
}
_variable = variable;
}
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo,
/// Note that it returns another reference to the variable, not a reference
/// to a new variable...
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
PSNoteProperty property = new PSVariableProperty(_variable);
CloneBaseProperties(property);
return property;
}
/// <summary>
/// Gets PSMemberTypes.NoteProperty
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.NoteProperty;
}
}
/// <summary>
/// True if the underlying variable is settable...
/// </summary>
public override bool IsSettable
{
get
{
return (_variable.Options & (ScopedItemOptions.Constant | ScopedItemOptions.ReadOnly)) == ScopedItemOptions.None;
}
}
/// <summary>
/// Gets true since the value of an PSNoteProperty can always be obtained
/// </summary>
public override bool IsGettable
{
get
{
return true;
}
}
/// <summary>
/// Gets or sets the value of this property
/// </summary>
public override object Value
{
get
{
return _variable.Value;
}
set
{
if (!this.IsInstance)
{
throw new SetValueException("ChangeValueOfStaticNote",
null,
ExtendedTypeSystem.ChangeStaticMember,
this.Name);
}
_variable.Value = value;
}
}
/// <summary>
/// Gets the type of the value for this member
/// </summary>
public override string TypeNameOfValue
{
get
{
object val = _variable.Value;
if (val == null)
{
return typeof(object).FullName;
}
PSObject valAsPSObject = val as PSObject;
if (valAsPSObject != null)
{
var typeNames = valAsPSObject.InternalTypeNames;
if ((typeNames != null) && (typeNames.Count >= 1))
{
// type name at 0-th index is the most specific type (i.e. system.string)
// type names at other indices are less specific (i.e. system.object)
return typeNames[0];
}
}
return val.GetType().FullName;
}
}
#endregion virtual implementation
}
/// <summary>
/// Serves as a property implemented with getter and setter scripts.
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSScriptProperty"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSScriptProperty : PSPropertyInfo
{
/// <summary>
/// Returns the string representation of this property
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.TypeNameOfValue);
returnValue.Append(" ");
returnValue.Append(this.Name);
returnValue.Append(" {");
if (this.IsGettable)
{
returnValue.Append("get=");
returnValue.Append(this.GetterScript.ToString());
returnValue.Append(";");
}
if (this.IsSettable)
{
returnValue.Append("set=");
returnValue.Append(this.SetterScript.ToString());
returnValue.Append(";");
}
returnValue.Append("}");
return returnValue.ToString();
}
2016-07-29 13:02:49 -07:00
private Nullable<PSLanguageMode> _languageMode;
private string _getterScriptText;
private ScriptBlock _getterScript;
2016-07-29 13:02:49 -07:00
private string _setterScriptText;
private ScriptBlock _setterScript;
private bool _shouldCloneOnAccess;
/// <summary>
/// Gets the script used for the property getter. It might be null.
/// </summary>
public ScriptBlock GetterScript
{
get
{
// If we don't have a script block for the getter, see if we
// have the text for it (to support delayed script compilation).
2016-07-29 13:02:49 -07:00
if ((_getterScript == null) && (_getterScriptText != null))
{
2016-07-29 13:02:49 -07:00
_getterScript = ScriptBlock.Create(_getterScriptText);
2016-07-29 13:02:49 -07:00
if (_languageMode.HasValue)
{
2016-07-29 13:02:49 -07:00
_getterScript.LanguageMode = _languageMode;
}
2016-07-29 13:02:49 -07:00
_getterScript.DebuggerStepThrough = true;
}
2016-07-29 13:02:49 -07:00
if (_getterScript == null)
{
return null;
}
2016-07-29 13:02:49 -07:00
if (_shouldCloneOnAccess)
{
// returning a clone as TypeTable might be shared between multiple
// runspaces and ScriptBlock is not shareable. We decided to
// Clone as needed instead of Cloning whenever a shared TypeTable is
// attached to a Runspace to save on Memory.
2016-07-29 13:02:49 -07:00
ScriptBlock newGetterScript = _getterScript.Clone();
newGetterScript.LanguageMode = _getterScript.LanguageMode;
return newGetterScript;
}
else
{
2016-07-29 13:02:49 -07:00
return _getterScript;
}
}
}
/// <summary>
/// Gets the script used for the property setter. It might be null.
/// </summary>
public ScriptBlock SetterScript
{
get
{
// If we don't have a script block for the setter, see if we
// have the text for it (to support delayed script compilation).
2016-07-29 13:02:49 -07:00
if ((_setterScript == null) && (_setterScriptText != null))
{
2016-07-29 13:02:49 -07:00
_setterScript = ScriptBlock.Create(_setterScriptText);
2016-07-29 13:02:49 -07:00
if (_languageMode.HasValue)
{
2016-07-29 13:02:49 -07:00
_setterScript.LanguageMode = _languageMode;
}
2016-07-29 13:02:49 -07:00
_setterScript.DebuggerStepThrough = true;
}
2016-07-29 13:02:49 -07:00
if (_setterScript == null)
{
return null;
}
2016-07-29 13:02:49 -07:00
if (_shouldCloneOnAccess)
{
// returning a clone as TypeTable might be shared between multiple
// runspaces and ScriptBlock is not shareable. We decided to
// Clone as needed instead of Cloning whenever a shared TypeTable is
// attached to a Runspace to save on Memory.
2016-07-29 13:02:49 -07:00
ScriptBlock newSetterScript = _setterScript.Clone();
newSetterScript.LanguageMode = _setterScript.LanguageMode;
return newSetterScript;
}
else
{
2016-07-29 13:02:49 -07:00
return _setterScript;
}
}
}
/// <summary>
/// Initializes an instance of the PSScriptProperty class as a read only property.
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="getterScript">script to be used for the property getter. $this will be this PSObject.</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSScriptProperty(string name, ScriptBlock getterScript)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterScript == null)
{
throw PSTraceSource.NewArgumentNullException("getterScript");
}
2016-07-29 13:02:49 -07:00
_getterScript = getterScript;
}
/// <summary>
/// Initializes an instance of the PSScriptProperty class as a read only
/// property. getterScript or setterScript can be null, but not both.
/// </summary>
/// <param name="name">Name of this property</param>
/// <param name="getterScript">script to be used for the property getter. $this will be this PSObject.</param>
/// <param name="setterScript">script to be used for the property setter. $this will be this PSObject and $args(1) will be the value to set.</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSScriptProperty(string name, ScriptBlock getterScript, ScriptBlock setterScript)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterScript == null && setterScript == null)
{
// we only do not allow both getterScript and setterScript to be null
throw PSTraceSource.NewArgumentException("getterScript setterScript");
}
if (getterScript != null)
{
getterScript.DebuggerStepThrough = true;
}
if (setterScript != null)
{
setterScript.DebuggerStepThrough = true;
}
2016-07-29 13:02:49 -07:00
_getterScript = getterScript;
_setterScript = setterScript;
}
/// <summary>
/// Initializes an instance of the PSScriptProperty class as a read only
/// property, using the text of the properties to support lazy initialization.
/// </summary>
/// <param name="name">Name of this property</param>
/// <param name="getterScript">script to be used for the property getter. $this will be this PSObject.</param>
/// <param name="setterScript">script to be used for the property setter. $this will be this PSObject and $args(1) will be the value to set.</param>
/// <param name="languageMode">Language mode to be used during script block evaluation.</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal PSScriptProperty(string name, string getterScript, string setterScript, Nullable<PSLanguageMode> languageMode)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (getterScript == null && setterScript == null)
{
// we only do not allow both getterScript and setterScript to be null
throw PSTraceSource.NewArgumentException("getterScript setterScript");
}
2016-07-29 13:02:49 -07:00
_getterScriptText = getterScript;
_setterScriptText = setterScript;
_languageMode = languageMode;
}
internal PSScriptProperty(string name, ScriptBlock getterScript, ScriptBlock setterScript, bool shouldCloneOnAccess)
2016-07-29 13:02:49 -07:00
: this(name, getterScript, setterScript)
{
2016-07-29 13:02:49 -07:00
_shouldCloneOnAccess = shouldCloneOnAccess;
}
internal PSScriptProperty(string name, string getterScript, string setterScript, Nullable<PSLanguageMode> languageMode, bool shouldCloneOnAccess)
: this(name, getterScript, setterScript, languageMode)
{
2016-07-29 13:02:49 -07:00
_shouldCloneOnAccess = shouldCloneOnAccess;
}
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
PSScriptProperty property;
property = new PSScriptProperty(name, this.GetterScript, this.SetterScript);
2016-07-29 13:02:49 -07:00
property._shouldCloneOnAccess = _shouldCloneOnAccess;
CloneBaseProperties(property);
return property;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.ScriptProperty;
}
}
/// <summary>
/// Gets true if this property can be set
/// </summary>
public override bool IsSettable
{
get
{
return this.SetterScript != null;
}
}
/// <summary>
/// Gets true if this property can be read
/// </summary>
public override bool IsGettable
{
get
{
return this.GetterScript != null;
}
}
/// <summary>
/// Gets and Sets the value of this property
/// </summary>
/// <exception cref="GetValueException">When getting and there is no getter,
/// when the getter throws an exception or when there is no Runspace to run the script.
/// </exception>
/// <exception cref="SetValueException">When setting and there is no setter,
/// when the setter throws an exception or when there is no Runspace to run the script.</exception>
public override object Value
{
get
{
if (this.GetterScript == null)
{
throw new GetValueException("GetWithoutGetterFromScriptPropertyValue",
null,
ExtendedTypeSystem.GetWithoutGetterException,
this.Name);
}
return InvokeGetter(this.instance);
}
set
{
if (this.SetterScript == null)
{
throw new SetValueException("SetWithoutSetterFromScriptProperty",
null,
ExtendedTypeSystem.SetWithoutSetterException,
this.Name);
}
InvokeSetter(this.instance, value);
}
}
internal object InvokeSetter(object scriptThis, object value)
{
try
{
SetterScript.DoInvokeReturnAsIs(
2016-07-29 13:02:49 -07:00
useLocalScope: true,
errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe,
dollarUnder: AutomationNull.Value,
input: AutomationNull.Value,
scriptThis: scriptThis,
args: new object[] { value });
return value;
}
catch (SessionStateOverflowException e)
{
throw NewSetValueException(e, "ScriptSetValueSessionStateOverflowException");
}
catch (RuntimeException e)
{
throw NewSetValueException(e, "ScriptSetValueRuntimeException");
}
catch (TerminateException)
{
// The debugger is terminating the execution; let the exception bubble up
throw;
}
catch (FlowControlException e)
{
throw NewSetValueException(e, "ScriptSetValueFlowControlException");
}
catch (PSInvalidOperationException e)
{
throw NewSetValueException(e, "ScriptSetValueInvalidOperationException");
}
}
internal object InvokeGetter(object scriptThis)
{
try
{
return GetterScript.DoInvokeReturnAsIs(
2016-07-29 13:02:49 -07:00
useLocalScope: true,
errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.SwallowErrors,
dollarUnder: AutomationNull.Value,
input: AutomationNull.Value,
scriptThis: scriptThis,
args: Utils.EmptyArray<object>());
}
catch (SessionStateOverflowException e)
{
throw NewGetValueException(e, "ScriptGetValueSessionStateOverflowException");
}
catch (RuntimeException e)
{
throw NewGetValueException(e, "ScriptGetValueRuntimeException");
}
catch (TerminateException)
{
// The debugger is terminating the execution; let the exception bubble up
throw;
}
catch (FlowControlException e)
{
throw NewGetValueException(e, "ScriptGetValueFlowControlException");
}
catch (PSInvalidOperationException e)
{
throw NewGetValueException(e, "ScriptgetValueInvalidOperationException");
}
}
/// <summary>
/// Gets the type of the value for this member. Currently this always returns typeof(object).FullName.
/// </summary>
public override string TypeNameOfValue
{
get
{
if ((this.GetterScript != null) &&
(this.GetterScript.OutputType.Count > 0))
{
return this.GetterScript.OutputType[0].Name;
}
else
{
return typeof(object).FullName;
}
}
}
#endregion virtual implementation
}
internal class PSMethodInvocationConstraints
{
internal PSMethodInvocationConstraints(
Type methodTargetType,
Type[] parameterTypes)
{
this.MethodTargetType = methodTargetType;
2016-07-29 13:02:49 -07:00
_parameterTypes = parameterTypes;
}
/// <remarks>
/// If <c>null</c> then there are no constraints
/// </remarks>
public Type MethodTargetType { get; private set; }
/// <remarks>
/// If <c>null</c> then there are no constraints
/// </remarks>
public IEnumerable<Type> ParameterTypes
{
get
{
2016-07-29 13:02:49 -07:00
return _parameterTypes;
}
}
2016-07-29 13:02:49 -07:00
private readonly Type[] _parameterTypes;
internal static bool EqualsForCollection<T>(ICollection<T> xs, ICollection<T> ys)
{
if (xs == null)
{
return ys == null;
}
if (ys == null)
{
return false;
}
if (xs.Count != ys.Count)
{
return false;
}
return xs.SequenceEqual(ys);
}
// TODO: IEnumerable<Type> genericTypeParameters { get; private set; }
public bool Equals(PSMethodInvocationConstraints other)
{
if (ReferenceEquals(null, other))
{
return false;
}
if (ReferenceEquals(this, other))
{
return true;
}
if (other.MethodTargetType != this.MethodTargetType)
{
return false;
}
2016-07-29 13:02:49 -07:00
if (!EqualsForCollection(_parameterTypes, other._parameterTypes))
{
return false;
}
return true;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
if (ReferenceEquals(this, obj))
{
return true;
}
2016-07-29 13:02:49 -07:00
if (obj.GetType() != typeof(PSMethodInvocationConstraints))
{
return false;
}
2016-07-29 13:02:49 -07:00
return Equals((PSMethodInvocationConstraints)obj);
}
public override int GetHashCode()
{
// algorithm based on http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
unchecked
{
int result = 61;
2016-07-29 13:02:49 -07:00
result = result * 397 + (MethodTargetType != null ? MethodTargetType.GetHashCode() : 0);
result = result * 397 + ParameterTypes.SequenceGetHashCode();
return result;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
string separator = "";
if (MethodTargetType != null)
{
sb.Append("this: ");
sb.Append(ToStringCodeMethods.Type(MethodTargetType, dropNamespaces: true));
separator = " ";
}
2016-07-29 13:02:49 -07:00
if (_parameterTypes != null)
{
sb.Append(separator);
sb.Append("args: ");
separator = "";
2016-07-29 13:02:49 -07:00
foreach (var p in _parameterTypes)
{
sb.Append(separator);
sb.Append(ToStringCodeMethods.Type(p, dropNamespaces: true));
separator = ", ";
}
}
if (sb.Length == 0)
{
sb.Append("<empty>");
}
return sb.ToString();
}
}
/// <summary>
/// Serves as a base class for all members that behave like methods.
/// </summary>
public abstract class PSMethodInfo : PSMemberInfo
{
/// <summary>
/// Initializes a new instance of a class derived from PSMethodInfo.
/// </summary>
protected PSMethodInfo() { }
/// <summary>
/// Invokes the appropriate method overload for the given arguments and returns its result.
/// </summary>
/// <param name="arguments">arguments to the method</param>
/// <returns>return value from the method</returns>
/// <exception cref="ArgumentException">if arguments is null</exception>
/// <exception cref="MethodException">For problems finding an appropriate method for the arguments</exception>
/// <exception cref="MethodInvocationException">For exceptions invoking the method.
/// This exception is also thrown for an <see cref="PSScriptMethod"/> when there is no Runspace to run the script.</exception>
public abstract object Invoke(params object[] arguments);
/// <summary>
/// Gets a list of all the overloads for this method
/// </summary>
2016-07-29 13:02:49 -07:00
public abstract Collection<string> OverloadDefinitions { get; }
#region virtual implementation
/// <summary>
/// Gets the value of this member. The getter returns the PSMethodInfo itself.
/// </summary>
/// <exception cref="ExtendedTypeSystemException">When setting the member</exception>
/// <remarks>
/// This is not the returned value of the method even for Methods with no arguments.
/// The getter returns this (the PSMethodInfo itself). The setter is not supported.
/// </remarks>
public sealed override object Value
{
get
{
return this;
}
set
{
2016-07-29 13:02:49 -07:00
throw new ExtendedTypeSystemException("CannotChangePSMethodInfoValue",
null,
2016-07-29 13:02:49 -07:00
ExtendedTypeSystem.CannotSetValueForMemberType,
this.GetType().FullName);
}
}
#endregion virtual implementation
}
/// <summary>
/// Serves as a method implemented with a reference to another method.
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSCodeMethod"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSCodeMethod : PSMethodInfo
{
/// <summary>
/// Returns the string representation of this member
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
foreach (string overload in OverloadDefinitions)
{
returnValue.Append(overload);
returnValue.Append(", ");
}
returnValue.Remove(returnValue.Length - 2, 2);
return returnValue.ToString();
}
2016-07-29 13:02:49 -07:00
private MethodInformation[] _codeReferenceMethodInformation;
internal static bool CheckMethodInfo(MethodInfo method)
{
ParameterInfo[] parameters = method.GetParameters();
return method.IsStatic
&& method.IsPublic
&& parameters.Length != 0
&& parameters[0].ParameterType == typeof(PSObject);
}
internal void SetCodeReference(Type type, string methodName)
{
MethodInfo methodAsMember = null;
try
{
methodAsMember = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase);
}
catch (AmbiguousMatchException)
{
// Ignore the AmbiguousMatchException.
// We will generate error below if we cannot find exactly one match method.
}
2016-07-29 13:02:49 -07:00
if (methodAsMember == null)
{
throw new ExtendedTypeSystemException("WrongMethodFormatFromTypeTable", null,
ExtendedTypeSystem.CodeMethodMethodFormat);
}
2016-08-02 13:29:09 -07:00
CodeReference = methodAsMember;
if (!CheckMethodInfo(CodeReference))
{
throw new ExtendedTypeSystemException("WrongMethodFormat", null, ExtendedTypeSystem.CodeMethodMethodFormat);
}
}
/// <summary>
/// Used from TypeTable
/// </summary>
internal PSCodeMethod(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
}
/// <summary>
/// Initializes a new instance of the PSCodeMethod class.
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="codeReference">this should be a public static method where the first parameter is an PSObject.</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
/// <exception cref="ExtendedTypeSystemException">if the codeReference does not have the right format</exception>
public PSCodeMethod(string name, MethodInfo codeReference)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
if (codeReference == null)
{
throw PSTraceSource.NewArgumentNullException("codeReference");
}
if (!CheckMethodInfo(codeReference))
{
throw new ExtendedTypeSystemException("WrongMethodFormat", null, ExtendedTypeSystem.CodeMethodMethodFormat);
}
2016-07-29 13:02:49 -07:00
this.name = name;
2016-08-02 13:29:09 -07:00
CodeReference = codeReference;
}
/// <summary>
/// Gets the method referenced by this PSCodeMethod
/// </summary>
2016-08-02 13:29:09 -07:00
public MethodInfo CodeReference { get; private set; }
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
2016-08-02 13:29:09 -07:00
PSCodeMethod member = new PSCodeMethod(name, CodeReference);
CloneBaseProperties(member);
return member;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.CodeMethod;
}
}
/// <summary>
/// Invokes CodeReference method and returns its results.
/// </summary>
/// <param name="arguments">arguments to the method</param>
/// <returns>return value from the method</returns>
/// <exception cref="ArgumentException">if arguments is null</exception>
/// <exception cref="MethodException">
/// When
/// could CodeReference cannot match the given argument count or
/// could not convert an argument to the type required
/// </exception>
/// <exception cref="MethodInvocationException">For exceptions invoking the CodeReference</exception>
public override object Invoke(params object[] arguments)
{
if (arguments == null)
{
throw PSTraceSource.NewArgumentNullException("arguments");
}
object[] newArguments = new object[arguments.Length + 1];
newArguments[0] = this.instance;
for (int i = 0; i < arguments.Length; i++)
{
newArguments[i + 1] = arguments[i];
}
2016-07-29 13:02:49 -07:00
if (_codeReferenceMethodInformation == null)
{
2016-08-02 13:29:09 -07:00
_codeReferenceMethodInformation = DotNetAdapter.GetMethodInformationArray(new[] { CodeReference });
}
object[] convertedArguments;
2016-08-02 13:29:09 -07:00
Adapter.GetBestMethodAndArguments(CodeReference.Name, _codeReferenceMethodInformation, newArguments, out convertedArguments);
2016-07-29 13:02:49 -07:00
return DotNetAdapter.AuxiliaryMethodInvoke(null, convertedArguments, _codeReferenceMethodInformation[0], newArguments);
}
/// <summary>
/// Gets the definition for CodeReference
/// </summary>
public override Collection<string> OverloadDefinitions
{
get
{
return new Collection<string>
{
2016-08-02 13:29:09 -07:00
DotNetAdapter.GetMethodInfoOverloadDefinition(null, CodeReference, 0)
};
}
}
/// <summary>
/// Gets the type of the value for this member. Currently this always returns typeof(PSCodeMethod).FullName.
/// </summary>
public override string TypeNameOfValue
{
get
{
return typeof(PSCodeMethod).FullName;
}
}
#endregion virtual implementation
}
/// <summary>
/// Serves as a method implemented with a script
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSScriptMethod"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSScriptMethod : PSMethodInfo
{
/// <summary>
/// Returns the string representation of this member
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.TypeNameOfValue);
returnValue.Append(" ");
returnValue.Append(this.Name);
returnValue.Append("();");
return returnValue.ToString();
}
2016-07-29 13:02:49 -07:00
private ScriptBlock _script;
private bool _shouldCloneOnAccess;
/// <summary>
/// Gets the script implementing this PSScriptMethod
/// </summary>
public ScriptBlock Script
{
get
{
2016-07-29 13:02:49 -07:00
if (_shouldCloneOnAccess)
{
// returning a clone as TypeTable might be shared between multiple
// runspaces and ScriptBlock is not shareable. We decided to
// Clone as needed instead of Cloning whenever a shared TypeTable is
// attached to a Runspace to save on Memory.
2016-07-29 13:02:49 -07:00
ScriptBlock newScript = _script.Clone();
newScript.LanguageMode = _script.LanguageMode;
return newScript;
}
else
{
2016-07-29 13:02:49 -07:00
return _script;
}
}
}
/// <summary>
/// Initializes a new instance of PSScriptMethod
/// </summary>
/// <param name="name">name of the method</param>
/// <param name="script">script to be used when calling the method.</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSScriptMethod(string name, ScriptBlock script)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (script == null)
{
throw PSTraceSource.NewArgumentNullException("script");
}
2016-07-29 13:02:49 -07:00
_script = script;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <param name="script"></param>
/// <param name="shouldCloneOnAccess">
/// Used by TypeTable.
/// TypeTable might be shared between multiple runspaces and
/// ScriptBlock is not shareable. We decided to Clone as needed
/// instead of Cloning whenever a shared TypeTable is attached
/// to a Runspace to save on Memory.
/// </param>
internal PSScriptMethod(string name, ScriptBlock script, bool shouldCloneOnAccess)
: this(name, script)
{
2016-07-29 13:02:49 -07:00
_shouldCloneOnAccess = shouldCloneOnAccess;
}
#region virtual implementation
/// <summary>
/// Invokes Script method and returns its results.
/// </summary>
/// <param name="arguments">arguments to the method</param>
/// <returns>return value from the method</returns>
/// <exception cref="ArgumentException">if arguments is null</exception>
/// <exception cref="MethodInvocationException">For exceptions invoking the Script or if there is no Runspace to run the script.</exception>
public override object Invoke(params object[] arguments)
{
if (arguments == null)
{
throw PSTraceSource.NewArgumentNullException("arguments");
}
2016-07-29 13:02:49 -07:00
return InvokeScript(Name, _script, this.instance, arguments);
}
2016-08-01 13:33:07 -07:00
internal static object InvokeScript(string methodName, ScriptBlock script, object @this, object[] arguments)
{
try
{
return script.DoInvokeReturnAsIs(
2016-07-29 13:02:49 -07:00
useLocalScope: true,
errorHandlingBehavior: ScriptBlock.ErrorHandlingBehavior.WriteToExternalErrorPipe,
2016-07-29 13:02:49 -07:00
dollarUnder: AutomationNull.Value,
input: AutomationNull.Value,
scriptThis: @this,
args: arguments);
}
catch (SessionStateOverflowException e)
{
throw new MethodInvocationException(
"ScriptMethodSessionStateOverflowException",
e,
ExtendedTypeSystem.MethodInvocationException,
methodName, arguments.Length, e.Message);
}
catch (RuntimeException e)
{
throw new MethodInvocationException(
"ScriptMethodRuntimeException",
e,
ExtendedTypeSystem.MethodInvocationException,
methodName, arguments.Length, e.Message);
}
catch (TerminateException)
{
// The debugger is terminating the execution; let the exception bubble up
throw;
}
catch (FlowControlException e)
{
throw new MethodInvocationException(
"ScriptMethodFlowControlException",
e,
ExtendedTypeSystem.MethodInvocationException,
methodName, arguments.Length, e.Message);
}
catch (PSInvalidOperationException e)
{
throw new MethodInvocationException(
"ScriptMethodInvalidOperationException",
e,
ExtendedTypeSystem.MethodInvocationException,
methodName, arguments.Length, e.Message);
}
}
/// <summary>
/// Gets a list of all the overloads for this method
/// </summary>
2016-07-29 13:02:49 -07:00
public override Collection<string> OverloadDefinitions
{
get
{
Collection<string> retValue = new Collection<string>();
retValue.Add(this.ToString());
return retValue;
}
}
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
PSScriptMethod method;
2016-07-29 13:02:49 -07:00
method = new PSScriptMethod(this.name, _script);
method._shouldCloneOnAccess = _shouldCloneOnAccess;
CloneBaseProperties(method);
return method;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.ScriptMethod;
}
}
/// <summary>
/// Gets the type of the value for this member. Currently this always returns typeof(object).FullName.
/// </summary>
public override string TypeNameOfValue
{
get
{
return typeof(object).FullName;
}
}
#endregion virtual implementation
}
/// <summary>
/// Used to access the adapted or base methods from the BaseObject
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSMethod"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSMethod : PSMethodInfo
{
internal override void ReplicateInstance(object particularInstance)
{
base.ReplicateInstance(particularInstance);
baseObject = particularInstance;
}
/// <summary>
/// Returns the string representation of this member
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
2016-07-29 13:02:49 -07:00
return _adapter.BaseMethodToString(this);
}
internal object adapterData;
2016-07-29 13:02:49 -07:00
private Adapter _adapter;
internal object baseObject;
/// <summary>
/// Constructs this method
/// </summary>
/// <param name="name">name</param>
/// <param name="adapter">adapter to be used invoking</param>
/// <param name="baseObject">baseObject for the methods</param>
/// <param name="adapterData">adapterData from adapter.GetMethodData</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal PSMethod(string name, Adapter adapter, object baseObject, object adapterData)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
this.adapterData = adapterData;
2016-07-29 13:02:49 -07:00
_adapter = adapter;
this.baseObject = baseObject;
}
/// <summary>
/// Constructs a PSMethod
/// </summary>
/// <param name="name">name</param>
/// <param name="adapter">adapter to be used invoking</param>
/// <param name="baseObject">baseObject for the methods</param>
/// <param name="adapterData">adapterData from adapter.GetMethodData</param>
/// <param name="isSpecial">true if this member is a special member, false otherwise.</param>
/// <param name="isHidden">true if this member is hidden, false otherwise.</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal PSMethod(string name, Adapter adapter, object baseObject, object adapterData, bool isSpecial, bool isHidden)
: this(name, adapter, baseObject, adapterData)
{
this.IsSpecial = isSpecial;
this.IsHidden = isHidden;
}
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
2016-07-29 13:02:49 -07:00
PSMethod member = new PSMethod(this.name, _adapter, this.baseObject, this.adapterData, this.IsSpecial, this.IsHidden);
CloneBaseProperties(member);
return member;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.Method;
}
}
/// <summary>
/// Invokes the appropriate method overload for the given arguments and returns its result.
/// </summary>
/// <param name="arguments">arguments to the method</param>
/// <returns>return value from the method</returns>
/// <exception cref="ArgumentException">if arguments is null</exception>
/// <exception cref="MethodException">For problems finding an appropriate method for the arguments</exception>
/// <exception cref="MethodInvocationException">For exceptions invoking the method</exception>
public override object Invoke(params object[] arguments)
{
return this.Invoke(null, arguments);
}
/// <summary>
/// Invokes the appropriate method overload for the given arguments and returns its result.
/// </summary>
/// <param name="invocationConstraints">constraints </param>
/// <param name="arguments">arguments to the method</param>
/// <returns>return value from the method</returns>
/// <exception cref="ArgumentException">if arguments is null</exception>
/// <exception cref="MethodException">For problems finding an appropriate method for the arguments</exception>
/// <exception cref="MethodInvocationException">For exceptions invoking the method</exception>
internal object Invoke(PSMethodInvocationConstraints invocationConstraints, params object[] arguments)
{
if (arguments == null)
{
throw PSTraceSource.NewArgumentNullException("arguments");
}
2016-07-29 13:02:49 -07:00
return _adapter.BaseMethodInvoke(this, invocationConstraints, arguments);
}
/// <summary>
/// Gets a list of all the overloads for this method
/// </summary>
public override Collection<string> OverloadDefinitions
{
get
{
2016-07-29 13:02:49 -07:00
return _adapter.BaseMethodDefinitions(this);
}
}
/// <summary>
/// Gets the type of the value for this member. This always returns typeof(PSMethod).FullName.
/// </summary>
public override string TypeNameOfValue
{
get
{
return typeof(PSMethod).FullName;
}
}
#endregion virtual implementation
/// <summary>
/// True if the method is a special method like GET/SET property accessor methods.
/// </summary>
internal bool IsSpecial { get; private set; }
}
/// <summary>
/// Used to access parameterized properties from the BaseObject
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSParameterizedProperty"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSParameterizedProperty : PSMethodInfo
{
/// <summary>
/// Returns the string representation of this member
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
Diagnostics.Assert((this.baseObject != null) && (this.adapter != null) && (this.adapterData != null), "it should have all these properties set");
return this.adapter.BaseParameterizedPropertyToString(this);
}
internal Adapter adapter;
internal object adapterData;
internal object baseObject;
/// <summary>
/// Constructs this parameterized proprerty
/// </summary>
/// <param name="name">name of the property</param>
/// <param name="adapter">adapter used in DoGetMethod</param>
/// <param name="baseObject">object passed to DoGetMethod</param>
/// <param name="adapterData">adapter specific data</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal PSParameterizedProperty(string name, Adapter adapter, object baseObject, object adapterData)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
this.adapter = adapter;
this.adapterData = adapterData;
this.baseObject = baseObject;
}
internal PSParameterizedProperty(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
}
/// <summary>
/// Gets true if this property can be set
/// </summary>
public bool IsSettable
{
get
{
return adapter.BaseParameterizedPropertyIsSettable(this);
}
}
/// <summary>
/// Gets true if this property can be read
/// </summary>
public bool IsGettable
{
get
{
return adapter.BaseParameterizedPropertyIsGettable(this);
}
}
#region virtual implementation
/// <summary>
/// Invokes the getter method and returns its result
/// </summary>
/// <param name="arguments">arguments to the method</param>
/// <returns>return value from the method</returns>
/// <exception cref="ArgumentException">if arguments is null</exception>
/// <exception cref="GetValueException">When getting the value of a property throws an exception</exception>
public override object Invoke(params object[] arguments)
{
if (arguments == null)
{
throw PSTraceSource.NewArgumentNullException("arguments");
}
return this.adapter.BaseParameterizedPropertyGet(this, arguments);
}
/// <summary>
/// Invokes the setter method
/// </summary>
/// <param name="valueToSet">value to set this property with</param>
/// <param name="arguments">arguments to the method</param>
/// <exception cref="ArgumentException">if arguments is null</exception>
/// <exception cref="SetValueException">When setting the value of a property throws an exception</exception>
public void InvokeSet(object valueToSet, params object[] arguments)
{
if (arguments == null)
{
throw PSTraceSource.NewArgumentNullException("arguments");
}
this.adapter.BaseParameterizedPropertySet(this, valueToSet, arguments);
}
2016-07-29 13:02:49 -07:00
/// <summary>
/// Returns a collection of the definitions for this property
/// </summary>
2016-07-29 13:02:49 -07:00
public override Collection<string> OverloadDefinitions
{
get
{
return adapter.BaseParameterizedPropertyDefinitions(this);
}
}
/// <summary>
/// Gets the type of the value for this member.
/// </summary>
public override string TypeNameOfValue
{
get
{
return adapter.BaseParameterizedPropertyType(this);
}
}
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
PSParameterizedProperty property = new PSParameterizedProperty(this.name, this.adapter, this.baseObject, this.adapterData);
CloneBaseProperties(property);
return property;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.ParameterizedProperty;
}
}
#endregion virtual implementation
}
/// <summary>
/// Serves as a set of members
/// </summary>
public class PSMemberSet : PSMemberInfo
{
internal override void ReplicateInstance(object particularInstance)
{
base.ReplicateInstance(particularInstance);
foreach (var member in Members)
{
member.ReplicateInstance(particularInstance);
}
}
/// <summary>
/// Returns the string representation of this member
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(" {");
foreach (PSMemberInfo member in this.Members)
{
returnValue.Append(member.Name);
returnValue.Append(", ");
}
if (returnValue.Length > 2)
{
returnValue.Remove(returnValue.Length - 2, 2);
}
returnValue.Insert(0, this.Name);
returnValue.Append("}");
return returnValue.ToString();
}
2016-07-29 13:02:49 -07:00
private PSMemberInfoIntegratingCollection<PSMemberInfo> _members;
private PSMemberInfoIntegratingCollection<PSPropertyInfo> _properties;
private PSMemberInfoIntegratingCollection<PSMethodInfo> _methods;
internal PSMemberInfoInternalCollection<PSMemberInfo> internalMembers;
2016-07-29 13:02:49 -07:00
private PSObject _constructorPSObject;
2016-07-29 13:02:49 -07:00
private static Collection<CollectionEntry<PSMemberInfo>> s_emptyMemberCollection = new Collection<CollectionEntry<PSMemberInfo>>();
private static Collection<CollectionEntry<PSMethodInfo>> s_emptyMethodCollection = new Collection<CollectionEntry<PSMethodInfo>>();
private static Collection<CollectionEntry<PSPropertyInfo>> s_emptyPropertyCollection = new Collection<CollectionEntry<PSPropertyInfo>>();
/// <summary>
/// Initializes a new instance of PSMemberSet with no initial members
/// </summary>
/// <param name="name">name for the member set</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSMemberSet(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
this.internalMembers = new PSMemberInfoInternalCollection<PSMemberInfo>();
2016-07-29 13:02:49 -07:00
_members = new PSMemberInfoIntegratingCollection<PSMemberInfo>(this, s_emptyMemberCollection);
_properties = new PSMemberInfoIntegratingCollection<PSPropertyInfo>(this, s_emptyPropertyCollection);
_methods = new PSMemberInfoIntegratingCollection<PSMethodInfo>(this, s_emptyMethodCollection);
}
/// <summary>
/// Initializes a new instance of PSMemberSet with all the initial members in <paramref name="members"/>
/// </summary>
/// <param name="name">name for the member set</param>
/// <param name="members">members in the member set</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSMemberSet(string name, IEnumerable<PSMemberInfo> members)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (members == null)
{
throw PSTraceSource.NewArgumentNullException("members");
}
this.internalMembers = new PSMemberInfoInternalCollection<PSMemberInfo>();
foreach (PSMemberInfo member in members)
{
if (member == null)
{
throw PSTraceSource.NewArgumentNullException("members");
}
this.internalMembers.Add(member.Copy());
}
2016-07-29 13:02:49 -07:00
_members = new PSMemberInfoIntegratingCollection<PSMemberInfo>(this, s_emptyMemberCollection);
_properties = new PSMemberInfoIntegratingCollection<PSPropertyInfo>(this, s_emptyPropertyCollection);
_methods = new PSMemberInfoIntegratingCollection<PSMethodInfo>(this, s_emptyMethodCollection);
}
2016-07-29 13:02:49 -07:00
private static Collection<CollectionEntry<PSMemberInfo>> s_typeMemberCollection = GetTypeMemberCollection();
private static Collection<CollectionEntry<PSMethodInfo>> s_typeMethodCollection = GetTypeMethodCollection();
private static Collection<CollectionEntry<PSPropertyInfo>> s_typePropertyCollection = GetTypePropertyCollection();
private static Collection<CollectionEntry<PSMemberInfo>> GetTypeMemberCollection()
{
Collection<CollectionEntry<PSMemberInfo>> returnValue = new Collection<CollectionEntry<PSMemberInfo>>();
returnValue.Add(new CollectionEntry<PSMemberInfo>(
PSObject.TypeTableGetMembersDelegate<PSMemberInfo>,
PSObject.TypeTableGetMemberDelegate<PSMemberInfo>,
true, true, "type table members"));
return returnValue;
}
private static Collection<CollectionEntry<PSMethodInfo>> GetTypeMethodCollection()
{
Collection<CollectionEntry<PSMethodInfo>> returnValue = new Collection<CollectionEntry<PSMethodInfo>>();
returnValue.Add(new CollectionEntry<PSMethodInfo>(
PSObject.TypeTableGetMembersDelegate<PSMethodInfo>,
PSObject.TypeTableGetMemberDelegate<PSMethodInfo>,
true, true, "type table members"));
return returnValue;
}
private static Collection<CollectionEntry<PSPropertyInfo>> GetTypePropertyCollection()
{
Collection<CollectionEntry<PSPropertyInfo>> returnValue = new Collection<CollectionEntry<PSPropertyInfo>>();
returnValue.Add(new CollectionEntry<PSPropertyInfo>(
PSObject.TypeTableGetMembersDelegate<PSPropertyInfo>,
PSObject.TypeTableGetMemberDelegate<PSPropertyInfo>,
true, true, "type table members"));
return returnValue;
}
/// <summary>
/// Used to create the Extended MemberSet
/// </summary>
/// <param name="name">name of the memberSet</param>
/// <param name="mshObject">object associated with this memberset</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal PSMemberSet(string name, PSObject mshObject)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (mshObject == null)
{
throw PSTraceSource.NewArgumentNullException("mshObject");
}
2016-07-29 13:02:49 -07:00
_constructorPSObject = mshObject;
this.internalMembers = mshObject.InstanceMembers;
2016-07-29 13:02:49 -07:00
_members = new PSMemberInfoIntegratingCollection<PSMemberInfo>(this, s_typeMemberCollection);
_properties = new PSMemberInfoIntegratingCollection<PSPropertyInfo>(this, s_typePropertyCollection);
_methods = new PSMemberInfoIntegratingCollection<PSMethodInfo>(this, s_typeMethodCollection);
}
internal bool inheritMembers = true;
/// <summary>
/// Gets a flag indicating whether the memberset will inherit members of the memberset
/// of the same name in the "parent" class.
/// </summary>
public bool InheritMembers
{
get
{
return this.inheritMembers;
}
}
/// <summary>
/// Gets the internal member collection
/// </summary>
internal virtual PSMemberInfoInternalCollection<PSMemberInfo> InternalMembers
{
get { return this.internalMembers; }
}
/// <summary>
/// Gets the member collection
/// </summary>
public PSMemberInfoCollection<PSMemberInfo> Members
{
get
{
2016-07-29 13:02:49 -07:00
return _members;
}
}
/// <summary>
/// Gets the Property collection, or the members that are actually properties.
/// </summary>
public PSMemberInfoCollection<PSPropertyInfo> Properties
{
get
{
2016-07-29 13:02:49 -07:00
return _properties;
}
}
/// <summary>
/// Gets the Method collection, or the members that are actually methods.
/// </summary>
public PSMemberInfoCollection<PSMethodInfo> Methods
{
get
{
2016-07-29 13:02:49 -07:00
return _methods;
}
}
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
2016-07-29 13:02:49 -07:00
if (_constructorPSObject == null)
{
PSMemberSet memberSet = new PSMemberSet(name);
foreach (PSMemberInfo member in this.Members)
{
memberSet.Members.Add(member);
}
CloneBaseProperties(memberSet);
return memberSet;
}
else
{
2016-07-29 13:02:49 -07:00
return new PSMemberSet(name, _constructorPSObject);
}
}
/// <summary>
/// Gets the member type. For PSMemberSet the member type is PSMemberTypes.MemberSet.
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.MemberSet;
}
}
/// <summary>
/// Gets the value of this member. The getter returns the PSMemberSet itself.
/// </summary>
/// <exception cref="ExtendedTypeSystemException">When trying to set the property</exception>
public override object Value
{
get
{
return this;
}
set
{
throw new ExtendedTypeSystemException("CannotChangePSMemberSetValue", null,
ExtendedTypeSystem.CannotSetValueForMemberType, this.GetType().FullName);
}
}
/// <summary>
/// Gets the type of the value for this member. This returns typeof(PSMemberSet).FullName.
/// </summary>
public override string TypeNameOfValue
{
get
{
return typeof(PSMemberSet).FullName;
}
}
#endregion virtual implementation
}
/// <summary>
/// This MemberSet is used internally to represent the memberset for properties
/// PSObject, PSBase, PSAdapted members of a PSObject. Having a specialized
/// memberset enables delay loading the members for these members. This saves
/// time loading the members of a PSObject.
/// </summary>
/// <remarks>
/// This is added to improve hosting PowerShell's PSObjects in a ASP.Net GridView
/// Control
/// </remarks>
internal class PSInternalMemberSet : PSMemberSet
{
2016-07-29 13:02:49 -07:00
private object _syncObject = new Object();
private PSObject _psObject;
#region Constructor
/// <summary>
/// Constructs the specialized member set.
/// </summary>
/// <param name="propertyName">
/// Should be one of PSObject, PSBase, PSAdapted
/// </param>
/// <param name="psObject">
/// original PSObject to use to generate members
/// </param>
internal PSInternalMemberSet(string propertyName, PSObject psObject)
: base(propertyName)
{
this.internalMembers = null;
2016-07-29 13:02:49 -07:00
_psObject = psObject;
}
#endregion
#region virtual overrides
/// <summary>
/// Generates the members when needed.
/// </summary>
internal override PSMemberInfoInternalCollection<PSMemberInfo> InternalMembers
{
get
{
// do not cache "psadapted"
if (name.Equals(PSObject.AdaptedMemberSetName, StringComparison.OrdinalIgnoreCase))
{
return GetInternalMembersFromAdapted();
}
// cache "psbase" and "psobject"
if (null == internalMembers)
{
2016-07-29 13:02:49 -07:00
lock (_syncObject)
{
if (null == internalMembers)
{
internalMembers = new PSMemberInfoInternalCollection<PSMemberInfo>();
switch (name.ToLowerInvariant())
{
case PSObject.BaseObjectMemberSetName:
GenerateInternalMembersFromBase();
break;
case PSObject.PSObjectMemberSetName:
GenerateInternalMembersFromPSObject();
2016-07-29 13:02:49 -07:00
break;
default:
Diagnostics.Assert(false,
string.Format(CultureInfo.InvariantCulture,
"PSInternalMemberSet cannot process {0}", name));
break;
}
}
}
}
return internalMembers;
}
}
#endregion
#region Private Methods
private void GenerateInternalMembersFromBase()
{
2016-07-29 13:02:49 -07:00
if (_psObject.isDeserialized)
{
2016-07-29 13:02:49 -07:00
if (_psObject.clrMembers != null)
{
2016-07-29 13:02:49 -07:00
foreach (PSMemberInfo member in _psObject.clrMembers)
{
internalMembers.Add(member.Copy());
}
}
}
else
{
foreach (PSMemberInfo member in
2016-07-29 13:02:49 -07:00
PSObject.dotNetInstanceAdapter.BaseGetMembers<PSMemberInfo>(_psObject.ImmediateBaseObject))
{
internalMembers.Add(member.Copy());
}
}
}
private PSMemberInfoInternalCollection<PSMemberInfo> GetInternalMembersFromAdapted()
{
PSMemberInfoInternalCollection<PSMemberInfo> retVal = new PSMemberInfoInternalCollection<PSMemberInfo>();
2016-07-29 13:02:49 -07:00
if (_psObject.isDeserialized)
{
2016-07-29 13:02:49 -07:00
if (_psObject.adaptedMembers != null)
{
2016-07-29 13:02:49 -07:00
foreach (PSMemberInfo member in _psObject.adaptedMembers)
{
retVal.Add(member.Copy());
}
}
}
else
{
2016-07-29 13:02:49 -07:00
foreach (PSMemberInfo member in _psObject.InternalAdapter.BaseGetMembers<PSMemberInfo>(
_psObject.ImmediateBaseObject))
{
retVal.Add(member.Copy());
}
}
return retVal;
}
private void GenerateInternalMembersFromPSObject()
{
PSMemberInfoCollection<PSMemberInfo> members = PSObject.dotNetInstanceAdapter.BaseGetMembers<PSMemberInfo>(
2016-07-29 13:02:49 -07:00
_psObject);
foreach (PSMemberInfo member in members)
{
internalMembers.Add(member.Copy());
}
}
#endregion
}
/// <summary>
/// Serves as a list of property names
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSPropertySet"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSPropertySet : PSMemberInfo
{
/// <summary>
/// Returns the string representation of this member
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder returnValue = new StringBuilder();
returnValue.Append(this.Name);
returnValue.Append(" {");
2016-08-02 13:29:09 -07:00
if (ReferencedPropertyNames.Count != 0)
{
2016-08-02 13:29:09 -07:00
foreach (string property in ReferencedPropertyNames)
{
returnValue.Append(property);
returnValue.Append(", ");
}
returnValue.Remove(returnValue.Length - 2, 2);
}
returnValue.Append("}");
return returnValue.ToString();
}
/// <summary>
/// Initializes a new instance of PSPropertySet with a name and list of property names
/// </summary>
/// <param name="name">name of the set</param>
/// <param name="referencedPropertyNames">name of the properties in the set</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public PSPropertySet(string name, IEnumerable<string> referencedPropertyNames)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
this.name = name;
if (referencedPropertyNames == null)
{
throw PSTraceSource.NewArgumentNullException("referencedPropertyNames");
}
2016-08-02 13:29:09 -07:00
ReferencedPropertyNames = new Collection<string>();
foreach (string referencedPropertyName in referencedPropertyNames)
{
if (String.IsNullOrEmpty(referencedPropertyName))
{
throw PSTraceSource.NewArgumentException("referencedPropertyNames");
}
2016-08-02 13:29:09 -07:00
ReferencedPropertyNames.Add(referencedPropertyName);
}
}
/// <summary>
/// Gets the property names in this property set
/// </summary>
2016-08-02 13:29:09 -07:00
public Collection<string> ReferencedPropertyNames { get; }
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
2016-08-02 13:29:09 -07:00
PSPropertySet member = new PSPropertySet(name, ReferencedPropertyNames);
CloneBaseProperties(member);
return member;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.PropertySet;
}
}
/// <summary>
/// Gets the PSPropertySet itself.
/// </summary>
/// <exception cref="ExtendedTypeSystemException">When setting the member</exception>
public override object Value
{
get
{
return this;
}
set
{
throw new ExtendedTypeSystemException("CannotChangePSPropertySetValue", null,
ExtendedTypeSystem.CannotSetValueForMemberType, this.GetType().FullName);
}
}
/// <summary>
/// Gets the type of the value for this member. This returns typeof(PSPropertySet).FullName.
/// </summary>
public override string TypeNameOfValue
{
get
{
return typeof(PSPropertySet).FullName;
}
}
#endregion virtual implementation
}
/// <summary>
/// Used to access the adapted or base events from the BaseObject
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSMethod"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class PSEvent : PSMemberInfo
{
/// <summary>
/// Returns the string representation of this member
/// </summary>
/// <returns>This property as a string</returns>
public override string ToString()
{
StringBuilder eventDefinition = new StringBuilder();
eventDefinition.Append(this.baseEvent.ToString());
eventDefinition.Append("(");
int loopCounter = 0;
foreach (ParameterInfo parameter in baseEvent.EventHandlerType.GetMethod("Invoke").GetParameters())
{
if (loopCounter > 0)
eventDefinition.Append(", ");
eventDefinition.Append(parameter.ParameterType.ToString());
loopCounter++;
}
eventDefinition.Append(")");
return eventDefinition.ToString();
}
internal EventInfo baseEvent;
/// <summary>
/// Constructs this event
/// </summary>
/// <param name="baseEvent">The actual event</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal PSEvent(EventInfo baseEvent)
{
this.baseEvent = baseEvent;
this.name = baseEvent.Name;
}
#region virtual implementation
/// <summary>
/// returns a new PSMemberInfo that is a copy of this PSMemberInfo
/// </summary>
/// <returns>a new PSMemberInfo that is a copy of this PSMemberInfo</returns>
public override PSMemberInfo Copy()
{
PSEvent member = new PSEvent(this.baseEvent);
CloneBaseProperties(member);
return member;
}
/// <summary>
/// Gets the member type
/// </summary>
public override PSMemberTypes MemberType
{
get
{
return PSMemberTypes.Event;
}
}
/// <summary>
/// Gets the value of this member. The getter returns the
/// actual .NET event that this type wraps.
/// </summary>
/// <exception cref="ExtendedTypeSystemException">When setting the member</exception>
public sealed override object Value
{
get
{
return baseEvent;
}
set
{
throw new ExtendedTypeSystemException("CannotChangePSEventInfoValue", null,
ExtendedTypeSystem.CannotSetValueForMemberType, this.GetType().FullName);
}
}
/// <summary>
/// Gets the type of the value for this member. This always returns typeof(PSMethod).FullName.
/// </summary>
public override string TypeNameOfValue
{
get
{
return typeof(PSEvent).FullName;
}
}
#endregion virtual implementation
}
/// <summary>
/// A dynamic member
/// </summary>
public class PSDynamicMember : PSMemberInfo
{
internal PSDynamicMember(string name)
{
this.name = name;
}
/// <summary/>
public override string ToString()
{
return "dynamic " + Name;
}
/// <summary/>
public override PSMemberTypes MemberType
{
get { return PSMemberTypes.Dynamic; }
}
/// <summary/>
public override object Value
{
get { throw PSTraceSource.NewInvalidOperationException(); }
set { throw PSTraceSource.NewInvalidOperationException(); }
}
/// <summary/>
public override string TypeNameOfValue
{
get { return "dynamic"; }
}
/// <summary/>
public override PSMemberInfo Copy()
{
return new PSDynamicMember(Name);
}
}
#endregion PSMemberInfo
#region Member collection classes and its auxilliary classes
/// <summary>
/// /// This class is used in PSMemberInfoInternalCollection and ReadOnlyPSMemberInfoCollection
/// </summary>
internal class MemberMatch
{
internal static WildcardPattern GetNamePattern(string name)
{
if (name != null && WildcardPattern.ContainsWildcardCharacters(name))
{
return WildcardPattern.Get(name, WildcardOptions.IgnoreCase);
}
return null;
}
/// <summary>
/// Returns all members in memberList matching name and memberTypes
/// </summary>
/// <param name="memberList">Members to look for member with the correct types and name.</param>
/// <param name="name">Name of the members to look for. The name might contain globbing characters</param>
/// <param name="nameMatch">WildcardPattern out of name</param>
/// <param name="memberTypes">type of members we want to retrieve</param>
/// <returns>A collection of members of the right types and name extracted from memberList.</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal static PSMemberInfoInternalCollection<T> Match<T>(PSMemberInfoInternalCollection<T> memberList, string name, WildcardPattern nameMatch, PSMemberTypes memberTypes) where T : PSMemberInfo
{
PSMemberInfoInternalCollection<T> returnValue = new PSMemberInfoInternalCollection<T>();
if (memberList == null)
{
throw PSTraceSource.NewArgumentNullException("memberList");
}
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
if (nameMatch == null)
{
T member = memberList[name];
if (member != null && (member.MemberType & memberTypes) != 0)
{
returnValue.Add(member);
}
return returnValue;
}
foreach (T member in memberList)
{
if (nameMatch.IsMatch(member.Name) && ((member.MemberType & memberTypes) != 0))
{
returnValue.Add(member);
}
}
return returnValue;
}
}
/// <summary>
/// Serves as the collection of members in an PSObject or MemberSet
/// </summary>
public abstract class PSMemberInfoCollection<T> : IEnumerable<T> where T : PSMemberInfo
{
#region ctor
/// <summary>
/// Initializes a new instance of an PSMemberInfoCollection derived class
/// </summary>
protected PSMemberInfoCollection()
{
}
#endregion ctor
#region abstract
/// <summary>
/// Adds a member to this collection
/// </summary>
/// <param name="member">member to be added</param>
/// <exception cref="ExtendedTypeSystemException">
/// When:
/// adding a member to an PSMemberSet from the type configuration file or
/// adding a member with a reserved member name or
/// trying to add a member with a type not compatible with this collection or
/// a member by this name is already present
/// </exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public abstract void Add(T member);
/// <summary>
/// Adds a member to this collection
/// </summary>
/// <param name="member">member to be added</param>
/// <param name="preValidated">flag to indicate that validation has already been done
/// on this new member. Use only when you can guarantee that the input will not
/// cause any of the errors normally caught by this method.</param>
/// <exception cref="ExtendedTypeSystemException">
/// When:
/// adding a member to an PSMemberSet from the type configuration file or
/// adding a member with a reserved member name or
/// trying to add a member with a type not compatible with this collection or
/// a member by this name is already present
/// </exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public abstract void Add(T member, bool preValidated);
/// <summary>
/// Removes a member from this collection
/// </summary>
/// <param name="name">name of the member to be removed</param>
/// <exception cref="ExtendedTypeSystemException">
/// When:
/// removing a member from an PSMemberSet from the type configuration file
/// removing a member with a reserved member name or
/// trying to remove a member with a type not compatible with this collection
/// </exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public abstract void Remove(string name);
/// <summary>
/// Gets the member in this collection matching name. If the member does not exist, null is returned.
/// </summary>
/// <param name="name">name of the member to look for</param>
/// <returns>the member matching name</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public abstract T this[string name]
{
get;
}
#endregion abstract
#region Match
/// <summary>
/// Returns all members in the collection matching name
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <returns>all members in the collection matching name</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public abstract ReadOnlyPSMemberInfoCollection<T> Match(string name);
/// <summary>
/// Returns all members in the collection matching name and types
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <param name="memberTypes">type of the members to be searched.</param>
/// <returns>all members in the collection matching name and types</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public abstract ReadOnlyPSMemberInfoCollection<T> Match(string name, PSMemberTypes memberTypes);
/// <summary>
/// Returns all members in the collection matching name and types
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <param name="memberTypes">type of the members to be searched.</param>
/// <param name="matchOptions">match options</param>
/// <returns>all members in the collection matching name and types</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal abstract ReadOnlyPSMemberInfoCollection<T> Match(string name, PSMemberTypes memberTypes, MshMemberMatchOptions matchOptions);
#endregion Match
internal static bool IsReservedName(string name)
{
return (String.Equals(name, PSObject.BaseObjectMemberSetName, StringComparison.OrdinalIgnoreCase) ||
String.Equals(name, PSObject.AdaptedMemberSetName, StringComparison.OrdinalIgnoreCase) ||
String.Equals(name, PSObject.ExtendedMemberSetName, StringComparison.OrdinalIgnoreCase) ||
String.Equals(name, PSObject.PSObjectMemberSetName, StringComparison.OrdinalIgnoreCase) ||
String.Equals(name, PSObject.PSTypeNames, StringComparison.OrdinalIgnoreCase));
}
#region IEnumerable
/// <summary>
/// Gets the general enumerator for this collection
/// </summary>
/// <returns>the enumerator for this collection</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Gets the specific enumerator for this collection.
/// </summary>
/// <returns>the enumerator for this collection</returns>
public abstract IEnumerator<T> GetEnumerator();
#endregion IEnumerable
}
/// <summary>
/// Serves as a read only collection of members
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="ReadOnlyPSMemberInfoCollection&lt;T&gt;"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class ReadOnlyPSMemberInfoCollection<T> : IEnumerable<T> where T : PSMemberInfo
{
2016-07-29 13:02:49 -07:00
private PSMemberInfoInternalCollection<T> _members;
/// <summary>
/// Initializes a new instance of ReadOnlyPSMemberInfoCollection with the given members
/// </summary>
/// <param name="members"></param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal ReadOnlyPSMemberInfoCollection(PSMemberInfoInternalCollection<T> members)
{
if (members == null)
{
throw PSTraceSource.NewArgumentNullException("members");
}
2016-07-29 13:02:49 -07:00
_members = members;
}
/// <summary>
/// Return the member in this collection matching name. If the member does not exist, null is returned.
/// </summary>
/// <param name="name">name of the member to look for</param>
/// <returns>the member matching name</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public T this[string name]
{
get
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
2016-07-29 13:02:49 -07:00
return _members[name];
}
}
/// <summary>
/// Returns all members in the collection matching name
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <returns>all members in the collection matching name</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public ReadOnlyPSMemberInfoCollection<T> Match(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
2016-07-29 13:02:49 -07:00
return _members.Match(name);
}
/// <summary>
/// Returns all members in the collection matching name and types
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <param name="memberTypes">type of the members to be searched.</param>
/// <returns>all members in the collection matching name and types</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public ReadOnlyPSMemberInfoCollection<T> Match(string name, PSMemberTypes memberTypes)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
2016-07-29 13:02:49 -07:00
return _members.Match(name, memberTypes);
}
/// <summary>
/// Gets the general enumerator for this collection
/// </summary>
/// <returns>the enumerator for this collection</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Gets the specific enumerator for this collection.
/// </summary>
/// <returns>the enumerator for this collection</returns>
public virtual IEnumerator<T> GetEnumerator()
{
2016-07-29 13:02:49 -07:00
return _members.GetEnumerator();
}
/// <summary>
/// Gets the number of elements in this collection
/// </summary>
2016-07-29 13:02:49 -07:00
public int Count { get { return _members.Count; } }
/// <summary>
/// Returns the 0 based member identified by index
/// </summary>
/// <param name="index">index of the member to retrieve</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
2016-07-29 13:02:49 -07:00
public T this[int index] { get { return _members[index]; } }
}
/// <summary>
/// Collection of members
/// </summary>
internal class PSMemberInfoInternalCollection<T> : PSMemberInfoCollection<T>, IEnumerable<T> where T : PSMemberInfo
{
2016-07-29 13:02:49 -07:00
private readonly OrderedDictionary _members;
private int _countHidden;
/// <summary>
/// Constructs this collection
/// </summary>
internal PSMemberInfoInternalCollection()
{
2016-07-29 13:02:49 -07:00
_members = new OrderedDictionary(StringComparer.OrdinalIgnoreCase);
}
private void Replace(T oldMember, T newMember)
{
2016-07-29 13:02:49 -07:00
_members[newMember.Name] = newMember;
if (oldMember.IsHidden)
{
2016-07-29 13:02:49 -07:00
_countHidden--;
}
if (newMember.IsHidden)
{
2016-07-29 13:02:49 -07:00
_countHidden++;
}
}
/// <summary>
/// Adds a member to the collection by replacing the one with the same name
/// </summary>
/// <param name="newMember"></param>
internal void Replace(T newMember)
{
Diagnostics.Assert(newMember != null, "called from internal code that checks for new member not null");
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
var oldMember = _members[newMember.Name] as T;
Diagnostics.Assert(oldMember != null, "internal code checks member already exists");
Replace(oldMember, newMember);
}
}
/// <summary>
/// Adds a member to this collection
/// </summary>
/// <param name="member">member to be added</param>
/// <exception cref="ExtendedTypeSystemException">when a member by this name is already present</exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override void Add(T member)
{
Add(member, false);
}
/// <summary>
/// Adds a member to this collection
/// </summary>
/// <param name="member">member to be added</param>
/// <param name="preValidated">flag to indicate that validation has already been done
/// on this new member. Use only when you can guarantee that the input will not
/// cause any of the errors normally caught by this method.</param>
/// <exception cref="ExtendedTypeSystemException">when a member by this name is already present</exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override void Add(T member, bool preValidated)
{
if (member == null)
{
throw PSTraceSource.NewArgumentNullException("member");
}
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
var existingMember = _members[member.Name] as T;
if (existingMember != null)
{
Replace(existingMember, member);
}
else
{
2016-07-29 13:02:49 -07:00
_members[member.Name] = member;
if (member.IsHidden)
{
2016-07-29 13:02:49 -07:00
_countHidden++;
}
}
}
}
/// <summary>
/// Removes a member from this collection
/// </summary>
/// <param name="name">name of the member to be removed</param>
/// <exception cref="ExtendedTypeSystemException">When removing a member with a reserved member name</exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override void Remove(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
if (IsReservedName(name))
{
throw new ExtendedTypeSystemException("PSMemberInfoInternalCollectionRemoveReservedName",
null,
ExtendedTypeSystem.ReservedMemberName,
name);
}
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
var member = _members[name] as PSMemberInfo;
if (member != null)
{
if (member.IsHidden)
{
2016-07-29 13:02:49 -07:00
_countHidden--;
}
2016-07-29 13:02:49 -07:00
_members.Remove(name);
}
}
}
/// <summary>
/// Returns the member in this collection matching name
/// </summary>
/// <param name="name">name of the member to look for</param>
/// <returns>the member matching name</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override T this[string name]
{
get
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
return _members[name] as T;
}
}
}
/// <summary>
/// Returns all members in the collection matching name
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <returns>all members in the collection matching name</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override ReadOnlyPSMemberInfoCollection<T> Match(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
return Match(name, PSMemberTypes.All, MshMemberMatchOptions.None);
}
/// <summary>
/// Returns all members in the collection matching name and types
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <param name="memberTypes">type of the members to be searched.</param>
/// <returns>all members in the collection matching name and types</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override ReadOnlyPSMemberInfoCollection<T> Match(string name, PSMemberTypes memberTypes)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
return Match(name, memberTypes, MshMemberMatchOptions.None);
}
/// <summary>
/// Returns all members in the collection matching name and types
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <param name="memberTypes">type of the members to be searched.</param>
/// <param name="matchOptions">match options</param>
/// <returns>all members in the collection matching name and types</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal override ReadOnlyPSMemberInfoCollection<T> Match(string name, PSMemberTypes memberTypes, MshMemberMatchOptions matchOptions)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
PSMemberInfoInternalCollection<T> internalMembers = GetInternalMembers(matchOptions);
return new ReadOnlyPSMemberInfoCollection<T>(MemberMatch.Match(internalMembers, name, MemberMatch.GetNamePattern(name), memberTypes));
}
private PSMemberInfoInternalCollection<T> GetInternalMembers(MshMemberMatchOptions matchOptions)
{
PSMemberInfoInternalCollection<T> returnValue = new PSMemberInfoInternalCollection<T>();
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
foreach (T member in _members.Values.OfType<T>())
{
if (member.MatchesOptions(matchOptions))
{
returnValue.Add(member);
}
}
}
return returnValue;
}
/// <summary>
/// The number of elements in this collection
/// </summary>
internal int Count
{
get
{
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
return _members.Count;
}
}
}
/// <summary>
/// The number of elements in this collection not marked as Hidden
/// </summary>
internal int VisibleCount
{
get
{
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
return _members.Count - _countHidden;
}
}
}
/// <summary>
/// Returns the 0 based member identified by index
/// </summary>
/// <param name="index">index of the member to retrieve</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal T this[int index]
{
get
{
2016-07-29 13:02:49 -07:00
lock (_members)
{
2016-07-29 13:02:49 -07:00
return _members[index] as T;
}
}
}
/// <summary>
/// Gets the specific enumerator for this collection.
/// This virtual works around the difficulty of implementing
/// interfaces virtually.
/// </summary>
/// <returns>the enumerator for this collection</returns>
public override IEnumerator<T> GetEnumerator()
{
2016-07-29 13:02:49 -07:00
lock (_members)
{
// Copy the members to a list so that iteration can be performed without holding a lock.
2016-07-29 13:02:49 -07:00
return _members.Values.OfType<T>().ToList().GetEnumerator();
}
}
}
#region CollectionEntry
2016-07-29 13:02:49 -07:00
internal class CollectionEntry<T> where T : PSMemberInfo
{
internal delegate PSMemberInfoInternalCollection<T> GetMembersDelegate(PSObject obj);
internal delegate T GetMemberDelegate(PSObject obj, string name);
internal CollectionEntry(GetMembersDelegate getMembers, GetMemberDelegate getMember,
bool shouldReplicateWhenReturning, bool shouldCloneWhenReturning, string collectionNameForTracing)
{
2016-08-02 13:29:09 -07:00
GetMembers = getMembers;
GetMember = getMember;
ShouldReplicateWhenReturning = shouldReplicateWhenReturning;
ShouldCloneWhenReturning = shouldCloneWhenReturning;
CollectionNameForTracing = collectionNameForTracing;
}
2016-08-02 13:29:09 -07:00
internal GetMembersDelegate GetMembers { get; }
2016-08-02 13:29:09 -07:00
internal GetMemberDelegate GetMember { get; }
2016-08-02 13:29:09 -07:00
internal bool ShouldReplicateWhenReturning { get; }
2016-08-02 13:29:09 -07:00
internal bool ShouldCloneWhenReturning { get; }
2016-08-02 13:29:09 -07:00
internal string CollectionNameForTracing { get; }
}
#endregion CollectionEntry
internal static class ReservedNameMembers
{
private static object GenerateMemberSet(string name, object obj)
{
PSObject mshOwner = PSObject.AsPSObject(obj);
var memberSet = mshOwner.InstanceMembers[name];
if (memberSet == null)
{
memberSet = new PSInternalMemberSet(name, mshOwner)
2016-07-29 13:02:49 -07:00
{
ShouldSerialize = false,
IsHidden = true,
IsReservedMember = true
};
mshOwner.InstanceMembers.Add(memberSet);
memberSet.instance = mshOwner;
}
return memberSet;
}
internal static object GeneratePSBaseMemberSet(object obj)
{
return GenerateMemberSet(PSObject.BaseObjectMemberSetName, obj);
}
internal static object GeneratePSAdaptedMemberSet(object obj)
{
2016-07-29 13:02:49 -07:00
return GenerateMemberSet(PSObject.AdaptedMemberSetName, obj);
}
internal static object GeneratePSObjectMemberSet(object obj)
{
return GenerateMemberSet(PSObject.PSObjectMemberSetName, obj);
}
internal static object GeneratePSExtendedMemberSet(object obj)
{
PSObject mshOwner = PSObject.AsPSObject(obj);
var memberSet = mshOwner.InstanceMembers[PSObject.ExtendedMemberSetName];
if (memberSet == null)
{
memberSet = new PSMemberSet(PSObject.ExtendedMemberSetName, mshOwner)
2016-07-29 13:02:49 -07:00
{
ShouldSerialize = false,
IsHidden = true,
IsReservedMember = true
};
memberSet.ReplicateInstance(mshOwner);
memberSet.instance = mshOwner;
mshOwner.InstanceMembers.Add(memberSet);
}
return memberSet;
}
// This is the implementation of the PSTypeNames CodeProperty.
public static Collection<string> PSTypeNames(PSObject o)
{
return o.TypeNames;
}
internal static void GeneratePSTypeNames(object obj)
{
PSObject mshOwner = PSObject.AsPSObject(obj);
if (null != mshOwner.InstanceMembers[PSObject.PSTypeNames])
{
// PSTypeNames member set is already generated..just return.
return;
}
PSCodeProperty codeProperty = new PSCodeProperty(PSObject.PSTypeNames, CachedReflectionInfo.ReservedNameMembers_PSTypeNames)
2016-07-29 13:02:49 -07:00
{
ShouldSerialize = false,
instance = mshOwner,
IsHidden = true,
IsReservedMember = true
};
mshOwner.InstanceMembers.Add(codeProperty);
}
}
internal class PSMemberInfoIntegratingCollection<T> : PSMemberInfoCollection<T>, IEnumerable<T> where T : PSMemberInfo
{
#region reserved names
private void GenerateAllReservedMembers()
{
2016-07-29 13:02:49 -07:00
if (!_mshOwner.hasGeneratedReservedMembers)
{
2016-07-29 13:02:49 -07:00
_mshOwner.hasGeneratedReservedMembers = true;
ReservedNameMembers.GeneratePSExtendedMemberSet(_mshOwner);
ReservedNameMembers.GeneratePSBaseMemberSet(_mshOwner);
ReservedNameMembers.GeneratePSObjectMemberSet(_mshOwner);
ReservedNameMembers.GeneratePSAdaptedMemberSet(_mshOwner);
ReservedNameMembers.GeneratePSTypeNames(_mshOwner);
}
}
#endregion reserved names
#region Constructor, fields and properties
2016-08-02 13:29:09 -07:00
internal Collection<CollectionEntry<T>> Collections { get; }
2016-07-29 13:02:49 -07:00
private PSObject _mshOwner;
private PSMemberSet _memberSetOwner;
internal PSMemberInfoIntegratingCollection(object owner, Collection<CollectionEntry<T>> collections)
{
if (owner == null)
{
throw PSTraceSource.NewArgumentNullException("owner");
}
2016-07-29 13:02:49 -07:00
_mshOwner = owner as PSObject;
_memberSetOwner = owner as PSMemberSet;
if (_mshOwner == null && _memberSetOwner == null)
{
throw PSTraceSource.NewArgumentException("owner");
}
if (collections == null)
{
throw PSTraceSource.NewArgumentNullException("collections");
}
2016-08-02 13:29:09 -07:00
Collections = collections;
}
#endregion Constructor, fields and properties
#region overrides
/// <summary>
/// Adds member to the collection
/// </summary>
/// <param name="member">member to be added</param>
/// <exception cref="ExtendedTypeSystemException">
/// When
/// member is an PSProperty or PSMethod
/// adding a member to a MemberSet with a reserved name
/// adding a member with a reserved member name or
/// adding a member with a type not compatible with this collection
/// a member with this name already exists
/// trying to add a member to a static memberset
/// </exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override void Add(T member)
{
Add(member, false);
}
/// <summary>
/// Adds member to the collection
/// </summary>
/// <param name="member">member to be added</param>
/// <param name="preValidated">flag to indicate that validation has already been done
/// on this new member. Use only when you can guarantee that the input will not
/// cause any of the errors normally caught by this method.</param>
/// <exception cref="ExtendedTypeSystemException">
/// When
/// member is an PSProperty or PSMethod
/// adding a member to a MemberSet with a reserved name
/// adding a member with a reserved member name or
/// adding a member with a type not compatible with this collection
/// a member with this name already exists
/// trying to add a member to a static memberset
/// </exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override void Add(T member, bool preValidated)
{
if (member == null)
{
throw PSTraceSource.NewArgumentNullException("member");
}
if (!preValidated)
{
if (member.MemberType == PSMemberTypes.Property || member.MemberType == PSMemberTypes.Method)
{
throw new ExtendedTypeSystemException(
"CannotAddMethodOrProperty",
null,
ExtendedTypeSystem.CannotAddPropertyOrMethod);
}
2016-07-29 13:02:49 -07:00
if (_memberSetOwner != null && _memberSetOwner.IsReservedMember)
{
throw new ExtendedTypeSystemException("CannotAddToReservedNameMemberset",
null,
ExtendedTypeSystem.CannotChangeReservedMember,
2016-07-29 13:02:49 -07:00
_memberSetOwner.Name);
}
}
AddToReservedMemberSet(member, preValidated);
}
/// <summary>
/// Auxiliary to add members from types.xml
/// </summary>
/// <param name="member"></param>
/// <param name="preValidated"></param>
internal void AddToReservedMemberSet(T member, bool preValidated)
{
2016-07-29 13:02:49 -07:00
if (!preValidated)
{
2016-07-29 13:02:49 -07:00
if (_memberSetOwner != null && !_memberSetOwner.IsInstance)
{
throw new ExtendedTypeSystemException("RemoveMemberFromStaticMemberSet",
null,
ExtendedTypeSystem.ChangeStaticMember,
member.Name);
}
}
AddToTypesXmlCache(member, preValidated);
}
/// <summary>
/// Adds member to the collection
/// </summary>
/// <param name="member">member to be added</param>
/// <param name="preValidated">flag to indicate that validation has already been done
/// on this new member. Use only when you can guarantee that the input will not
/// cause any of the errors normally caught by this method.</param>
/// <exception cref="ExtendedTypeSystemException">
/// When
/// adding a member with a reserved member name or
/// adding a member with a type not compatible with this collection
/// a member with this name already exists
/// trying to add a member to a static memberset
/// </exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal void AddToTypesXmlCache(T member, bool preValidated)
{
if (member == null)
{
throw PSTraceSource.NewArgumentNullException("member");
}
if (!preValidated)
{
if (IsReservedName(member.Name))
{
throw new ExtendedTypeSystemException("PSObjectMembersMembersAddReservedName",
null,
ExtendedTypeSystem.ReservedMemberName,
member.Name);
}
}
PSMemberInfo memberToBeAdded = member.Copy();
2016-07-29 13:02:49 -07:00
if (_mshOwner != null)
{
if (!preValidated)
{
2016-07-29 13:02:49 -07:00
TypeTable typeTable = _mshOwner.GetTypeTable();
if (typeTable != null)
{
2016-07-29 13:02:49 -07:00
PSMemberInfoInternalCollection<T> typesXmlMembers = typeTable.GetMembers<T>(_mshOwner.InternalTypeNames);
if (typesXmlMembers[member.Name] != null)
{
throw new ExtendedTypeSystemException(
"AlreadyPresentInTypesXml",
null,
ExtendedTypeSystem.MemberAlreadyPresentFromTypesXml,
member.Name);
}
}
}
2016-07-29 13:02:49 -07:00
memberToBeAdded.ReplicateInstance(_mshOwner);
_mshOwner.InstanceMembers.Add(memberToBeAdded, preValidated);
// All member binders may need to invalidate dynamic sites, and now must generate
// different binding restrictions (specifically, must check for an instance member
// before considering the type table or adapted members.)
PSGetMemberBinder.SetHasInstanceMember(memberToBeAdded.Name);
2016-07-29 13:02:49 -07:00
PSVariableAssignmentBinder.NoteTypeHasInstanceMemberOrTypeName(PSObject.Base(_mshOwner).GetType());
return;
}
2016-07-29 13:02:49 -07:00
_memberSetOwner.InternalMembers.Add(memberToBeAdded, preValidated);
}
/// <summary>
/// Removes the member named name from the collection
/// </summary>
/// <param name="name">Name of the member to be removed</param>
/// <exception cref="ExtendedTypeSystemException">
/// When trying to remove a member with a type not compatible with this collection
/// When trying to remove a member from a static memberset
/// When trying to remove a member from a MemberSet with a reserved name
/// </exception>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override void Remove(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
2016-07-29 13:02:49 -07:00
if (_mshOwner != null)
{
2016-07-29 13:02:49 -07:00
_mshOwner.InstanceMembers.Remove(name);
return;
}
2016-07-29 13:02:49 -07:00
if (!_memberSetOwner.IsInstance)
{
throw new ExtendedTypeSystemException("AddMemberToStaticMemberSet",
null,
ExtendedTypeSystem.ChangeStaticMember,
name);
}
2016-07-29 13:02:49 -07:00
if (IsReservedName(_memberSetOwner.Name))
{
throw new ExtendedTypeSystemException("CannotRemoveFromReservedNameMemberset",
null,
ExtendedTypeSystem.CannotChangeReservedMember,
2016-07-29 13:02:49 -07:00
_memberSetOwner.Name);
}
2016-07-29 13:02:49 -07:00
_memberSetOwner.InternalMembers.Remove(name);
}
/// <summary>
/// Method which checks if the <paramref name="name"/> is reserved and if so
/// it will ensure that the particular reserved member is loaded into the
/// objects member collection.
///
/// Caller should ensure that name is not null or empty.
/// </summary>
/// <param name="name">
/// Name of the member to check and load (if needed).
/// </param>
private void EnsureReservedMemberIsLoaded(string name)
{
Diagnostics.Assert(!String.IsNullOrEmpty(name),
"Name cannot be null or empty");
// Length >= psbase (shortest special member)
if (name.Length >= 6 && (name[0] == 'p' || name[0] == 'P') && (name[1] == 's' || name[1] == 'S'))
{
switch (name.ToLowerInvariant())
{
2016-07-29 13:02:49 -07:00
case PSObject.BaseObjectMemberSetName:
ReservedNameMembers.GeneratePSBaseMemberSet(_mshOwner);
break;
case PSObject.AdaptedMemberSetName:
ReservedNameMembers.GeneratePSAdaptedMemberSet(_mshOwner);
break;
case PSObject.ExtendedMemberSetName:
ReservedNameMembers.GeneratePSExtendedMemberSet(_mshOwner);
break;
case PSObject.PSObjectMemberSetName:
ReservedNameMembers.GeneratePSObjectMemberSet(_mshOwner);
break;
case PSObject.PSTypeNames:
ReservedNameMembers.GeneratePSTypeNames(_mshOwner);
break;
default:
break;
}
}
}
/// <summary>
/// Returns the name corresponding to name or null if it is not present
/// </summary>
/// <param name="name">name of the member to return</param>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override T this[string name]
{
get
{
using (PSObject.memberResolution.TraceScope("Lookup"))
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
PSMemberInfo member;
object delegateOwner;
2016-07-29 13:02:49 -07:00
if (_mshOwner != null)
{
// this will check if name is a reserved name like PSBase, PSTypeNames
// if it is a reserved name, ensures the value is loaded.
EnsureReservedMemberIsLoaded(name);
2016-07-29 13:02:49 -07:00
delegateOwner = _mshOwner;
PSMemberInfoInternalCollection<PSMemberInfo> instanceMembers;
2016-07-29 13:02:49 -07:00
if (PSObject.HasInstanceMembers(_mshOwner, out instanceMembers))
{
member = instanceMembers[name];
T memberAsT = member as T;
if (memberAsT != null)
{
PSObject.memberResolution.WriteLine("Found PSObject instance member: {0}.", name);
return memberAsT;
}
}
}
else
{
2016-07-29 13:02:49 -07:00
member = _memberSetOwner.InternalMembers[name];
delegateOwner = _memberSetOwner.instance;
T memberAsT = member as T;
if (memberAsT != null)
{
// In membersets we cannot replicate the instance when adding
// since the memberset might not yet have an associated PSObject.
// We replicate the instance when returning the members of the memberset.
PSObject.memberResolution.WriteLine("Found PSMemberSet member: {0}.", name);
member.ReplicateInstance(delegateOwner);
return memberAsT;
}
}
if (delegateOwner == null)
return null;
delegateOwner = PSObject.AsPSObject(delegateOwner);
2016-08-02 13:29:09 -07:00
foreach (CollectionEntry<T> collection in Collections)
{
Diagnostics.Assert(delegateOwner != null, "all integrating collections with non emtpty collections have an associated PSObject");
T memberAsT = collection.GetMember((PSObject)delegateOwner, name);
if (memberAsT != null)
{
if (collection.ShouldCloneWhenReturning)
{
memberAsT = (T)memberAsT.Copy();
}
if (collection.ShouldReplicateWhenReturning)
{
memberAsT.ReplicateInstance(delegateOwner);
}
return memberAsT;
}
}
return null;
}
}
}
private PSMemberInfoInternalCollection<T> GetIntegratedMembers(MshMemberMatchOptions matchOptions)
{
using (PSObject.memberResolution.TraceScope("Generating the total list of members"))
{
PSMemberInfoInternalCollection<T> returnValue = new PSMemberInfoInternalCollection<T>();
object delegateOwner;
2016-07-29 13:02:49 -07:00
if (_mshOwner != null)
{
2016-07-29 13:02:49 -07:00
delegateOwner = _mshOwner;
foreach (PSMemberInfo member in _mshOwner.InstanceMembers)
{
if (member.MatchesOptions(matchOptions))
{
T memberAsT = member as T;
if (memberAsT != null)
{
returnValue.Add(memberAsT);
}
}
}
}
else
{
2016-07-29 13:02:49 -07:00
delegateOwner = _memberSetOwner.instance;
foreach (PSMemberInfo member in _memberSetOwner.InternalMembers)
{
if (member.MatchesOptions(matchOptions))
{
T memberAsT = member as T;
if (memberAsT != null)
{
member.ReplicateInstance(delegateOwner);
returnValue.Add(memberAsT);
}
}
}
}
if (delegateOwner == null)
return returnValue;
delegateOwner = PSObject.AsPSObject(delegateOwner);
2016-08-02 13:29:09 -07:00
foreach (CollectionEntry<T> collection in Collections)
{
PSMemberInfoInternalCollection<T> members = collection.GetMembers((PSObject)delegateOwner);
foreach (T member in members)
{
PSMemberInfo previousMember = returnValue[member.Name];
if (previousMember != null)
{
PSObject.memberResolution.WriteLine("Member \"{0}\" of type \"{1}\" has been ignored because a member with the same name and type \"{2}\" is already present.",
member.Name, member.MemberType, previousMember.MemberType);
continue;
}
if (!member.MatchesOptions(matchOptions))
{
PSObject.memberResolution.WriteLine("Skipping hidden member \"{0}\".", member.Name);
continue;
}
T memberToAdd;
if (collection.ShouldCloneWhenReturning)
{
memberToAdd = (T)member.Copy();
}
else
{
memberToAdd = member;
}
if (collection.ShouldReplicateWhenReturning)
{
memberToAdd.ReplicateInstance(delegateOwner);
}
returnValue.Add(memberToAdd);
}
}
return returnValue;
}
}
/// <summary>
/// Returns all members in the collection matching name
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <returns>all members in the collection matching name</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override ReadOnlyPSMemberInfoCollection<T> Match(string name)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
return Match(name, PSMemberTypes.All, MshMemberMatchOptions.None);
}
/// <summary>
/// Returns all members in the collection matching name and types
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <param name="memberTypes">type of the members to be searched.</param>
/// <returns>all members in the collection matching name and types</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
public override ReadOnlyPSMemberInfoCollection<T> Match(string name, PSMemberTypes memberTypes)
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
return Match(name, memberTypes, MshMemberMatchOptions.None);
}
/// <summary>
/// Returns all members in the collection matching name and types
/// </summary>
/// <param name="name">name of the members to be return. May contain wildcard characters.</param>
/// <param name="memberTypes">type of the members to be searched.</param>
/// <param name="matchOptions">search options</param>
/// <returns>all members in the collection matching name and types</returns>
/// <exception cref="ArgumentException">for invalid arguments</exception>
internal override ReadOnlyPSMemberInfoCollection<T> Match(string name, PSMemberTypes memberTypes, MshMemberMatchOptions matchOptions)
{
using (PSObject.memberResolution.TraceScope("Matching \"{0}\"", name))
{
if (String.IsNullOrEmpty(name))
{
throw PSTraceSource.NewArgumentException("name");
}
2016-07-29 13:02:49 -07:00
if (_mshOwner != null)
{
GenerateAllReservedMembers();
}
WildcardPattern nameMatch = MemberMatch.GetNamePattern(name);
PSMemberInfoInternalCollection<T> allMembers = GetIntegratedMembers(matchOptions);
ReadOnlyPSMemberInfoCollection<T> returnValue = new ReadOnlyPSMemberInfoCollection<T>(MemberMatch.Match(allMembers, name, nameMatch, memberTypes));
PSObject.memberResolution.WriteLine("{0} total matches.", returnValue.Count);
return returnValue;
}
}
/// <summary>
/// Gets the specific enumerator for this collection.
/// This virtual works around the difficulty of implementing
/// interfaces virtually.
/// </summary>
/// <returns>the enumerator for this collection</returns>
public override IEnumerator<T> GetEnumerator()
{
return new Enumerator<T>(this);
}
#endregion overrides
/// <summary>
/// Enumerable for this class
/// </summary>
internal struct Enumerator<S> : IEnumerator<S> where S : PSMemberInfo
{
2016-07-29 13:02:49 -07:00
private S _current;
private int _currentIndex;
private PSMemberInfoInternalCollection<S> _allMembers;
/// <summary>
/// Constructs this instance to enumerate over members
/// </summary>
/// <param name="integratingCollection">members we are enumerating</param>
internal Enumerator(PSMemberInfoIntegratingCollection<S> integratingCollection)
{
using (PSObject.memberResolution.TraceScope("Enumeration Start"))
{
2016-07-29 13:02:49 -07:00
_currentIndex = -1;
_current = null;
_allMembers = integratingCollection.GetIntegratedMembers(MshMemberMatchOptions.None);
if (integratingCollection._mshOwner != null)
{
integratingCollection.GenerateAllReservedMembers();
2016-07-29 13:02:49 -07:00
PSObject.memberResolution.WriteLine("Enumerating PSObject with type \"{0}\".", integratingCollection._mshOwner.ImmediateBaseObject.GetType().FullName);
PSObject.memberResolution.WriteLine("PSObject instance members: {0}", _allMembers.VisibleCount);
}
else
{
2016-07-29 13:02:49 -07:00
PSObject.memberResolution.WriteLine("Enumerating PSMemberSet \"{0}\".", integratingCollection._memberSetOwner.Name);
PSObject.memberResolution.WriteLine("MemberSet instance members: {0}", _allMembers.VisibleCount);
}
}
}
/// <summary>
/// Moves to the next element in the enumeration
/// </summary>
/// <returns>
/// false if there are no more elements to enumerate
/// true otherwise
/// </returns>
public bool MoveNext()
{
2016-07-29 13:02:49 -07:00
_currentIndex++;
S member = null;
2016-07-29 13:02:49 -07:00
while (_currentIndex < _allMembers.Count)
{
2016-07-29 13:02:49 -07:00
member = _allMembers[_currentIndex];
if (!member.IsHidden)
{
break;
}
2016-07-29 13:02:49 -07:00
_currentIndex++;
}
2016-07-29 13:02:49 -07:00
if (_currentIndex < _allMembers.Count)
{
2016-07-29 13:02:49 -07:00
_current = member;
return true;
}
2016-07-29 13:02:49 -07:00
_current = null;
return false;
}
/// <summary>
/// Current PSMemberInfo in the enumeration
/// </summary>
/// <exception cref="ArgumentException">for invalid arguments</exception>
S IEnumerator<S>.Current
{
get
{
2016-07-29 13:02:49 -07:00
if (_currentIndex == -1)
{
throw PSTraceSource.NewInvalidOperationException();
}
2016-07-29 13:02:49 -07:00
return _current;
}
}
object IEnumerator.Current
{
get
{
return ((IEnumerator<S>)this).Current;
}
}
void IEnumerator.Reset()
{
2016-07-29 13:02:49 -07:00
_currentIndex = -1;
_current = null;
}
/// <summary>
/// Not supported
/// </summary>
public void Dispose() { }
}
}
#endregion Member collection classes and its auxilliary classes
}
#pragma warning restore 56503