开发者

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 no开发者_StackOverflow中文版t single.. can that be done ?


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.


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.


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

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


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.


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

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


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)


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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜