Rafael Herscovici
Rafael Herscovici

Reputation: 17124

Linq .SingleOrDefault - how to setup a default for a custom class?

i went over some questions and searched google a bit, but i couldnt find an answer ( That satisfies me ).

Basicly, i understand the SingleOrDefault return null or 0 ( depends on the type ).

but how can i make it return something else ?

return myChannels.All.Where(_Channel => _Channel.Guid == this.ParentChannelGuid).SingleOrDefault(_SPECIFICCHANNEL);

so, i want _SPECIFICCHANNEL to be returned in case it is not single.. can that be done ?

Upvotes: 11

Views: 9642

Answers (7)

d219
d219

Reputation: 2835

Expanding on Oskar's answer of an extension method you can make that more generic so that it covers value as well as reference types with something like the below:

    public static T SingleOrSpecifiedDefault<T>(this IEnumerable<T> enumerable, Expression<Func<T, bool>> singleOrDefault, T defaultValue) where T : IComparable
    {
        T singleValue = enumerable.SingleOrDefault(singleOrDefault.Compile());
        if (singleValue == null || singleValue.CompareTo(default(T)) == 0)
        {
            return defaultValue;
        }

        return singleValue;
    }

This allows you to specify the same LINQ expression that you'd use with SingleOrDefault as well as the defaultValue (which will be used if no match is found).

Upvotes: 0

Bill Gregg
Bill Gregg

Reputation: 7147

Why not just use the "??" operator and say

return myChannels.SingleOrDefault(_Channel => _Channel.Guid == this.ParentChannelGuid) ??_SPECIFICCHANNEL;

Upvotes: 4

Allon Guralnek
Allon Guralnek

Reputation: 16121

This can be accomplished in a rather simple way. If you create your own extension method that is more specific than the generic SingleOrDefault, then the compiler will prefer the more type-specific version. Here's an example that shows how to do that with a simple Person class (you can copy-paste it into LINQPad to quickly see the result):

public class Person
{
    public string Name { get; set; }

    public override string ToString()
    {
        return Name ?? "";
    }
}

public static class PersonExtensionMethod
{
    public static Person SingleOrDefault(this IEnumerable<Person> source)
    {
        var person = Enumerable.SingleOrDefault(source);

        if (person == null)
            return new Person { Name = "Unnamed" };

        return person;
    }
}

public static void Main()
{
    var emptyCollection = new Person[0];
    var nonEmptyCollection = new Person[] { new Person { Name = "Jack" } };

    Debug.WriteLine("Empty collection: " + emptyCollection.SingleOrDefault());
    Debug.WriteLine("Non-empty collection: " + nonEmptyCollection.SingleOrDefault());
}

In the above example, SingleOrDefault(IEnumerable<Person>), takes precedence over SingleOrDefault<T>(IEnumerable<T>) which is less specific.

Upvotes: 6

Jonas H&#248;gh
Jonas H&#248;gh

Reputation: 10874

You cannot define the default value of a type. It is always defined as null for reference types. For structs, it is an instance of the struct where all member fields in turn are set to their default values. For enums, it is always 0 (which may or may not be a defined value of the enum type in question)

Upvotes: 1

TomTom
TomTom

Reputation: 62137

but how can i make it return something else ?

You cannot. You can make your own method — as shown by Oskar Kjellin — to return someting else, but SingleOrDefault will always behave as programmed, which means return the default value (null, 0) for an item.

Upvotes: 4

Oskar Kjellin
Oskar Kjellin

Reputation: 21900

You will have to make an extension method:

    public static T SingleOr<T>(this IEnumerable<T> list, T defaultValue) where T : class
    {
        return list.SingleOrDefault() ?? defaultValue;
    }

There is no other way. All classes default to null.

Upvotes: 10

ipr101
ipr101

Reputation: 24236

Could you use DefaultIfEmpty() (psedo code follows) -

return myChannels.All.Where(_Channel => _Channel.Guid == this.ParentChannelGuid).DefaultIfEmpty(_SPECIFICCHANNEL).SingleOrDefault();

Upvotes: 5

Related Questions