Test enum for equality in for ... where clause
You can use if case
:
for status in statuses {
if case .failed = status {
...
}
}
But, unfortunately, you can't use case
with the where
clause of for
loop.
In this case, though, because you've defined .failed
to be equal to another regardless of what the error
associated value was, you theoretically could do:
for status in statuses where status == .failed(error: "") {
show("\(status)")
}
I'm not crazy about that pattern because (a) it's contingent upon the fact that .failed
values are equal even if they have different error
associated values; and (b) it results in code that is easily misunderstood.
How to test equality of Swift enums with associated values
Swift 4.1+
As @jedwidz has helpfully pointed out, from Swift 4.1 (due to SE-0185, Swift also supports synthesizing Equatable
and Hashable
for enums with associated values.
So if you're on Swift 4.1 or newer, the following will automatically synthesize the necessary methods such that XCTAssert(t1 == t2)
works. The key is to add the Equatable
protocol to your enum.
enum SimpleToken: Equatable {
case Name(String)
case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
Before Swift 4.1
As others have noted, Swift doesn't synthesize the necessary equality operators automatically. Let me propose a cleaner (IMHO) implementation, though:
enum SimpleToken: Equatable {
case Name(String)
case Number(Int)
}
public func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
switch (lhs, rhs) {
case let (.Name(a), .Name(b)),
let (.Number(a), .Number(b)):
return a == b
default:
return false
}
}
It's far from ideal — there's a lot of repetition — but at least you don't need to do nested switches with if-statements inside.
How to compare enum with associated values by ignoring its associated value in Swift?
Edit: As Etan points out, you can omit the (_)
wildcard match to use this more cleanly:
let number = CardRank.Number(5)
if case .Number = number {
// Is a number
} else {
// Something else
}
Unfortunately, I don't believe that there's an easier way than your switch
approach in Swift 1.2.
In Swift 2, however, you can use the new if-case
pattern match:
let number = CardRank.Number(5)
if case .Number(_) = number {
// Is a number
} else {
// Something else
}
If you're looking to avoid verbosity, you might consider adding an isNumber
computed property to your enum that implements your switch statement.
How to check if at least one enum value is equal to a variable within an if condition
A few options:
- You can define your enums as flags. This means each value must be a power of 2 (1, 2, 4, 8, etc). Then, you could write:
if (randomValue & (Values.Value1 | Values.Value2) > 0)
{
//...
}
- You can use a switch
switch (randomValue)
{
case Values.Value1:
case Values.Value2:
{
//Do something
break;
}
case Values.Value3:
//Do something else
break;
default:
break;
}
- You can use an array (nicer if you have predefined sets of values you want to search for).
if (new[] { Values.Value1, Values.Value2 }.Contains(randomValue))
{
}
or
static(?) readonly Values[] allowedValues = new[] { Values.Value1, Values.Value2 };
void MethodName(Values randomValue)
{
if (allowedValues.Contains(randomValue))
{
//...
}
}
How to do an if-else comparison on enums with arguments
The trick is to not actually check with == but rather use the case
keyword in conjunction with a single = in your if statement. This is a little counter intuitive in the beginning but just like if let
, you get used to it pretty fast:
enum Normal {
case one
case two, three
}
enum NormalRaw: Int {
case one = 1
case two, three
}
enum NormalArg {
case one(Int)
case two, three
}
let normalOne = Normal.one
let normalRawOne = NormalRaw.one
let normalArgOne = NormalArg.one(1)
if case .one = normalOne {
print("A normal one") //prints "A normal one"
}
if case .one = normalRawOne {
print("A normal \(normalRawOne.rawValue)") //prints "A normal 1"
}
if case .one(let value) = normalArgOne {
print("A normal \(value)") //prints "A normal 1"
}
The point is that in Swift you only get equation of enums for free if your enum uses a raw type or if you have no associated values (try it out, you can't have both at the same time). Swift however does not know how to compare cases with associated values - I mean how could it? Let's look at this example:
Normal.one == .one //true
Normal.one == .two //false
NormalRaw.one == .one //true
NormalRaw.one == .two //false
NormalArg.one(1) == .one(1) //Well...?
NormalArg.one(2) == .one(1) //Well...?
NormalArg.one(1) == .two //Well...?
Maybe this makes it clearer why this cannot work out of the box:
class Special {
var name: String?
var special: Special?
}
enum SpecialEnum {
case one(Special)
case two
}
var special1 = Special()
special1.name = "Hello"
var special2 = Special()
special2.name = "World"
special2.special = special1
SpecialEnum.one(special1) == SpecialEnum.one(special2) //Well...?
So if you want enums with associated values, you'll have to implement Equatable protocol in your enum by yourself:
enum NormalArg: Equatable {
case one(Int)
case two
static func ==(lhs: NormalArg, rhs: NormalArg) -> Bool {
switch (lhs, rhs) {
case (let .one(a1), let .one(a2)):
return a1 == a2
case (.two,.two):
return true
default:
return false
}
}
}
Error why matching an enumeration using a if statement
Enums that don't have associated types are automatically equatable. Enums that have associated types aren't. This makes sense, because only you can know how the associated type (such as the integer that comes with your .un
value) should be handled. Even though .trois
doesn't have an associated type, the lack of freebie equateableness affects the whole enum. Switch works a little differently, using pattern matching, so it still works.
If you want your enum with an associated type to be equatable, you can define your own ==
operator:
enum SomeType {
case un(Int)
case deux
case trois
}
// possibly there's a more succinct way to do this switch
func ==(lhs: SomeType, rhs: SomeType) -> Bool {
switch (lhs,rhs) {
case let (.un(i), .un(j)) where i == j: return true
case (.deux,.deux): return true
case (.trois, .trois): return true
default: return false
}
}
var testValue: SomeType = .trois
if testValue == .trois {
println("equals .trois")
}
// note, for SomeType to work with generic
// functions that require Equatable, you have
// to add that too:
extension SomeType: Equatable { }
// which means this will work:
let a: [SomeType] = [.un(1), .deux, .trois]
find(a, .trois)
Check enum for multiple values
I ended up writing a method:
public static enum FileType {
CSV, XML, XLS, TXT, FIXED_LENGTH;
// Java < 8
public boolean in(FileType... fileTypes) {
for(FileType fileType : fileTypes) {
if(this == fileType) {
return true;
}
}
return false;
}
// Java 8
public boolean in(FileType... fileTypes) {
return Arrays.stream(fileTypes).anyMatch(fileType -> fileType == this);
}
}
And then:
if(fileType.in(FileType.CSV, FileType.TXT, FileType.FIXED_LENGTH)) {}
Nice and clean!
How to compare enum and int values?
It doesn't matter which you use, they will perform identically. If there is no enum for an integer value, .net creates one at runtime. There can be no exceptions.
However, Xichen Li is correct - why would you want to compare an enum against an integer value?
Can I use case enum comparison as a boolean expression?
Unfortunately, you cannot (directly) use a case
condition as a Bool
expression. They are only accessible in statements such as if
, guard
, while
, for
etc.
This is detailed in the language grammar, with:
case-condition → case pattern initializer
This is then used in a condition
:
condition → expression | availability-condition | case-condition | optional-binding-condition
(where expression
represents a Bool
expression)
This is then used in condition-list
:
condition-list → condition | condition , condition-list
which is then used in statements such as if
:
if-statement → if condition-list code-block else-clause opt
So you can see that unfortunately case-condition
is not an expression, rather just a special condition you can use in given statements.
To pack it into an expression, you'll either have to use an immediately-evaluated closure:
return { if case .active = session.state { return true }; return false }()
Or otherwise write convenience computed properties on the enum
in order to get a Bool
in order to check for a given case, as shown in this Q&A.
Both of which are quite unsatisfactory. This has been filed as an improvement request, but nothing has come of it yet (at the time of posting). Hopefully it's something that will be possible in a future version of the language.
C# Enum - How to Compare Value
use this
if (userProfile.AccountType == AccountType.Retailer)
{
...
}
If you want to get int from your AccountType enum and compare it (don't know why) do this:
if((int)userProfile.AccountType == 1)
{
...
}
Objet reference not set to an instance of an object
exception is because your userProfile is null and you are getting property of null. Check in debug why it's not set.
EDIT (thanks to @Rik and @KonradMorawski) :
Maybe you can do some check before:
if(userProfile!=null)
{
}
or
if(userProfile==null)
{
throw new ArgumentNullException(nameof(userProfile)); // or any other exception
}
Related Topics
Storagemetadata' Has No Member 'Downloadurl'
How to Refresh The Google Map in My Application Using Swift
How to Spin and Add a Linear Force to an Entity Loaded from Reality Composer
Filter on Calayer Except for a Shape Which Is an Union of (Non Necessarily Distinct) Rectangles
Alamofire Https Change in 10.3
Xcode 13.1 Bug Editing Dependency as Local
Event Scrolling (Scrollviewdidscroll) Never Called - Swift 3
Swift 4 Date Picker Wrong Value Using Minuteinterval
Multiline Editable Text Field in Swiftui
How to Change The Data Type in Realm Database
Swiftui: UIimage (Qrcode) Does Not Load After Calling Function
Xcode Issue: Library Not Loaded: @Rpath/Libswiftappkit.Dylib
Swift: Using Member Constant as Default Value for Function Parameter
Accessing an Actor's Isolated State from Within a Swiftui View
Parametrized Unit Tests in Swift