From 5508aa32f5f7125aa1ef44ad330c7a1074ab2418 Mon Sep 17 00:00:00 2001 From: Manuel de la Pena Date: Mon, 16 May 2016 18:33:07 +0200 Subject: [PATCH] [Fix] Add missing selectors for NSExpression. Added the missing static factory methods and the missing property. In order to give a clean API a new flag was added to the NSExpression class to track if the Block property does return a block or a null ptr. The idea is to avoid user from seeing an obj-c exception. This commit fixes bug #35012: https://bugzilla.xamarin.com/show_bug.cgi?id=35012 The evaluation of the NSExpression and the defition of the NSExpressionHandler have also been fixed since both should be using NSObjects. --- src/Foundation/NSExpression.cs | 168 +++++++++++++++++++++++++++++++++ src/foundation.cs | 85 +++++++++++------ src/frameworks.sources | 1 + 3 files changed, 225 insertions(+), 29 deletions(-) create mode 100644 src/Foundation/NSExpression.cs diff --git a/src/Foundation/NSExpression.cs b/src/Foundation/NSExpression.cs new file mode 100644 index 000000000000..e91930706cb3 --- /dev/null +++ b/src/Foundation/NSExpression.cs @@ -0,0 +1,168 @@ +// TODO: The NSExpression class is a cluster class in cococa. This means that now all the properties are supported by all the types of NSExpressions. +// At the point of this written all the properties have been tested with all types EXCEPT NSExpressionType.Subquery and NSExpressionType.Conditional because writting +// tests for those was not possible. The properties for these two types have been deduced from the other types yet bugs are possible and an objc excection will be thrown. +using System; +using System.Runtime.InteropServices; +using XamCore.ObjCRuntime; + +namespace XamCore.Foundation { + + public partial class NSExpression { + + [Export ("arguments")] + public virtual NSExpression[] Arguments { + get { + var type = ExpressionType; + if (type != NSExpressionType.Function && type != NSExpressionType.Block && type != NSExpressionType.KeyPath) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the Arguments property. Expressions that support the property " + + "are of type Function, Block and KeyPath"); + return _Arguments; + } + } + + + [Export ("collection")] + public virtual NSObject Collection { + get { + var type = ExpressionType; + if (type != NSExpressionType.NSAggregate) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the Collection property. Expressions that support the property " + + "are of type NSAggregate"); + return _Collection; + } + } + + [Export ("predicate")] + public virtual NSPredicate Predicate { + get { + var type = ExpressionType; + if (type != NSExpressionType.Conditional && type != NSExpressionType.Subquery) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the Predicate property. Expressions that support the property " + + "are of type Conditional and Subquery"); + return _Predicate; + } + } + + [Export ("expressionBlock")] + public virtual NSExpressionCallbackHandler Block { + get { + if (ExpressionType != NSExpressionType.Block) + throw new InvalidOperationException ( + $"NSExpressions of type {ExpressionType} do not support the Block property. Expressions that support the property " + + "are created via the FromFunction (NSExpressionHandler target, NSExpression[] parameters) method."); + return _Block; + } + } + + [Export ("constantValue")] + public virtual NSObject ConstantValue { + get { + if (ExpressionType != NSExpressionType.ConstantValue) + throw new InvalidOperationException ( + $"NSExpressions of type {ExpressionType} do not support the ConstantValue property. Expressions that support the property " + + "are created via the FromConstant methods."); + return _ConstantValue; + } + } + + [Export ("keyPath")] + public virtual string KeyPath { + get { + if (ExpressionType != NSExpressionType.KeyPath) + throw new InvalidOperationException ( + $"NSExpressions of type {ExpressionType} do not support the KeyPath property. Expressions that support the property " + + "are created via the FromKeyPath method."); + return _KeyPath; + } + } + + [Export ("leftExpression")] + public virtual NSExpression LeftExpression { + get { + var type = ExpressionType; + if (type != NSExpressionType.Conditional && type != NSExpressionType.IntersectSet && type != NSExpressionType.MinusSet + && type != NSExpressionType.Subquery && type != NSExpressionType.UnionSet) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the LeftExpression property. Expressions that support the property " + + "are of type Conditional, IntersectSet, MinusSet, Subquery or UnionSet"); + return _LeftExpression; + } + } + + [Mac(10,11),iOS(9,0)] + [Export ("trueExpression")] + public virtual NSExpression TrueExpression { + get { + var type = ExpressionType; + if (type != NSExpressionType.Conditional && type != NSExpressionType.Subquery) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the TrueExpression property. Expressions that support the property " + + "are of type Conditional and Subquery"); + return _TrueExpression; + } + } + + [Mac(10,11),iOS(9,0)] + [Export ("falseExpression")] + public virtual NSExpression FalseExpression { + get { + var type = ExpressionType; + if (type != NSExpressionType.Conditional && type != NSExpressionType.Subquery) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the FalseExpression property. Expressions that support the property " + + "are of type Conditional and Subquery"); + return _FalseExpression; + } + } + + [Export ("rightExpression")] + public virtual NSExpression RightExpression { + get { + var type = ExpressionType; + if (type != NSExpressionType.Conditional && type != NSExpressionType.IntersectSet && type != NSExpressionType.MinusSet + && type != NSExpressionType.Subquery && type != NSExpressionType.UnionSet) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the RightExpression property. Expressions that support the property " + + "are of type Conditional, IntersectSet, MinusSet, Subquery or UnionSet"); + return _RightExpression; + } + } + + [Export ("function")] + public virtual string Function { + get { + if (ExpressionType != NSExpressionType.Function) + throw new InvalidOperationException ( + $"NSExpressions of type {ExpressionType} do not support the Function property. Expressions that support the property " + + "are created via the FromFunction (FromFunction (string name, NSExpression[] parameters) or FromFormat methods."); + return _Function; + } + } + + [Export ("variable")] + public virtual string Variable { + get { + if (ExpressionType != NSExpressionType.Variable) + throw new InvalidOperationException ( + $"NSExpressions of type {ExpressionType} do not support the Function property. Expressions that support the property " + + "are created via the FromVariable method."); + return _Variable; + } + } + + [Export ("operand")] + public virtual NSExpression Operand { + get { + var type = ExpressionType; + if (type != NSExpressionType.KeyPath && type != NSExpressionType.Function) + throw new InvalidOperationException ( + $"NSExpressions of type {type} do not support the Arguments property. Expressions that support the property " + + "are of type Function, Block and KeyPath"); + return _Operand; + } + } + } +} diff --git a/src/foundation.cs b/src/foundation.cs index f7bbc8b4bb30..390e684d07e7 100644 --- a/src/foundation.cs +++ b/src/foundation.cs @@ -3152,8 +3152,11 @@ public interface NSException : NSCoding, NSCopying { string[] CallStackSymbols { get; } } +#if !XAMCORE_4_0 + [Obsolete("NSExpressionHandler is deprecated, please use FromFormat (string, NSObject[]) instead.")] public delegate void NSExpressionHandler (NSObject evaluatedObject, NSExpression [] expressions, NSMutableDictionary context); - +#endif + public delegate NSObject NSExpressionCallbackHandler (NSObject evaluatedObject, NSExpression [] expressions, NSMutableDictionary context); [BaseType (typeof (NSObject))] // Objective-C exception thrown. Name: NSInvalidArgumentException Reason: *** -predicateFormat cannot be sent to an abstract object of class NSExpression: Create a concrete instance! [DisableDefaultCtor] @@ -3173,9 +3176,18 @@ public interface NSExpression : NSSecureCoding, NSCopying { [Static, Export ("expressionForFunction:arguments:")] NSExpression FromFunction (string name, NSExpression[] parameters); - [Static, Export ("expressionWithFormat:argumentArray:")] + [Static, Export ("expressionWithFormat:")] + NSExpression FromFormat (string expressionFormat); + +#if !XAMCORE_4_0 + [Obsolete("FromFormat (string, NSExpression[]) is deprecated, please use FromFormat (string, NSObject[]) instead.")] + [Sealed, Static, Export ("expressionWithFormat:argumentArray:")] NSExpression FromFormat (string format, NSExpression [] parameters); - +#endif + + [Static, Export ("expressionWithFormat:argumentArray:")] + NSExpression FromFormat (string format, NSObject [] parameters); + //+ (NSExpression *)expressionForAggregate:(NSArray *)subexpressions; [Static, Export ("expressionForAggregate:")] NSExpression FromAggregate (NSExpression [] subexpressions); @@ -3196,8 +3208,14 @@ public interface NSExpression : NSSecureCoding, NSCopying { [Static, Export ("expressionForFunction:selectorName:arguments:")] NSExpression FromFunction (NSExpression target, string name, NSExpression[] parameters); - [Static, Export ("expressionForBlock:arguments:")] +#if !XAMCORE_4_0 + [Obsolete("FromFunction (NSExpressionHandler, NSExpression[]) is deprecated, please use FromFunction (NSExpressionCallbackHandler, NSExpression[]) instead.")] + [Sealed, Static, Export ("expressionForBlock:arguments:")] NSExpression FromFunction (NSExpressionHandler target, NSExpression[] parameters); +#endif + + [Static, Export ("expressionForBlock:arguments:")] + NSExpression FromFunction (NSExpressionCallbackHandler target, NSExpression[] parameters); [Since (7,0), Mavericks] [Static] @@ -3220,46 +3238,55 @@ public interface NSExpression : NSSecureCoding, NSCopying { [Export ("expressionType")] NSExpressionType ExpressionType { get; } - [Export ("constantValue")] - NSObject ConstantValue { get; } + [Sealed, Internal, Export ("expressionBlock")] + NSExpressionCallbackHandler _Block { get; } - [Export ("keyPath")] - string KeyPath { get; } + [Sealed, Internal, Export ("constantValue")] + NSObject _ConstantValue { get; } - [Export ("function")] - string Function { get; } + [Sealed, Internal, Export ("keyPath")] + string _KeyPath { get; } - [Export ("variable")] - string Variable { get; } + [Sealed, Internal, Export ("function")] + string _Function { get; } - [Export ("operand")] - NSExpression Operand { get; } + [Sealed, Internal, Export ("variable")] + string _Variable { get; } - [Export ("arguments")] - NSExpression[] Arguments { get; } + [Sealed, Internal, Export ("operand")] + NSExpression _Operand { get; } - [Export ("collection")] - NSObject Collection { get; } + [Sealed, Internal, Export ("arguments")] + NSExpression[] _Arguments { get; } - [Export ("predicate")] - NSPredicate Predicate { get; } + [Sealed, Internal, Export ("collection")] + NSObject _Collection { get; } - [Export ("leftExpression")] - NSExpression LeftExpression { get; } + [Sealed, Internal, Export ("predicate")] + NSPredicate _Predicate { get; } - [Export ("rightExpression")] - NSExpression RightExpression { get; } + [Sealed, Internal, Export ("leftExpression")] + NSExpression _LeftExpression { get; } + + [Sealed, Internal, Export ("rightExpression")] + NSExpression _RightExpression { get; } [Mac(10,11),iOS(9,0)] - [Export ("trueExpression")] - NSExpression TrueExpression { get; } + [Sealed, Internal, Export ("trueExpression")] + NSExpression _TrueExpression { get; } [Mac(10,11),iOS(9,0)] - [Export ("falseExpression")] - NSExpression FalseExpression { get; } + [Sealed, Internal, Export ("falseExpression")] + NSExpression _FalseExpression { get; } + +#if !XAMCORE_4_0 + [Obsolete("ValueWithObject is deprecated, please use EvaluateWith instead.")] + [Sealed, Export ("expressionValueWithObject:context:")] + NSExpression ExpressionValueWithObject (NSObject object1, NSMutableDictionary context); +#endif [Export ("expressionValueWithObject:context:")] - NSExpression ExpressionValueWithObject (NSObject object1, NSMutableDictionary context); + NSObject EvaluateWith ([NullAllowed] NSObject obj, [NullAllowed] NSMutableDictionary context); } [iOS (8,0)][Mac (10,10, onlyOn64 : true)] // Not defined in 32-bit diff --git a/src/frameworks.sources b/src/frameworks.sources index 83a2e59b4575..6b033b1ddb30 100644 --- a/src/frameworks.sources +++ b/src/frameworks.sources @@ -623,6 +623,7 @@ FOUNDATION_SOURCES = \ Foundation/NSDirectoryEnumerator.cs \ Foundation/NSDistributedNotificationCenter.cs \ Foundation/NSErrorException.cs \ + Foundation/NSExpression.cs \ Foundation/NSExtension.cs \ Foundation/NSFastEnumerationState.cs \ Foundation/NSFastEnumerator.cs \