Ich habe eine Liste von Berechtigungen. Eine Berechtigungsklasse verfügt über vier Eigenschaften: Typ, AccessType, Wert und Aktion. Ich möchte eine Ausnahme auslösen, wenn es mehrere Berechtigungen gibt, bei denen Typ, Zugriffstyp und Wert gleich sind, ABER die Aktionen sind unterschiedlich.

So würde beispielsweise eine Liste von p1 und p2 eine Ausnahme auslösen:

Privilege p1 = new Privilege{Type = "a", AccessType = "a", Value = "a", Action = "a"};
Privilege p2 = new Privilege{Type = "a", AccessType = "a", Value = "a", Action = "b"};

Ich würde gerne LINQ verwenden, bin mir aber nicht sicher, wie.

3
fota666 18 Apr. 2018 im 12:12

4 Antworten

Beste Antwort

Sie möchten also einen doppelten Typ + Zugriffstyp + Wert zulassen, aber nur, wenn die Aktion auch dieselbe ist?

bool throwException = pList
    .GroupBy(x => new { x.Type, x.AccessType, x.Value })
    .Any(g => g.Select(p => p.Action).Distinct().Count() > 1);

Zuerst baue ich Gruppen dieser drei Eigenschaften. Dann überprüfe ich, ob eine dieser Gruppen mehrere Aktionen enthält. Dann können Sie die Ausnahme auslösen.

Eine kleine Optimierung kann sein (wenn die doppelten Listen groß sind), wenn Sie ersetzen

Distinct().Count() > 1

Mit

Distinct().Skip(1).Any()
3
Tim Schmelter 18 Apr. 2018 im 09:40

Es klingt so, als ob Sie nach Type, AccessType und Value gruppieren möchten (was Sie mit einem anonymen Typ tun können) und dann die Aktionen überprüfen möchten. Angenommen, es ist in Ordnung, Werte zu haben, bei denen Action in jedem Fall gleich ist, könnten Sie Code wie folgt schreiben:

// Normally I'd expect you to have some kind of sequence of privileges rather
// than separate variables.
var privileges = new[] { p1, p2 };
var failures = privileges
    // Group the privileges by 3 properties, extracting actions as the values
    .GroupBy(p => new { p.Type, p.AccessType, p.Value }, p => p.Action)
    // Find any groups which have more than one distinct action
    .Where(g => g.Distinct().Skip(1).Any())
    .ToList();

if (failures.Count > 0)
{
    // There's at least one failure. There may be many. Throw
    // whatever exception you want here. This is just an example.
    var individualMessages =
        failures.Select(g => $"{g.Key}: {string.Join(", ", g.Distinct())}");
    throw new Exception(
        $"Invalid privilege combinations: {string.Join("; ", individualMessages})");
}

Hier ist ein vollständiges Beispiel, das einige Fehler zeigt:

using System;
using System.Collections.Generic;
using System.Linq;

class Privilege
{
    public string Type { get; }
    public string AccessType { get; }
    public string Value { get; }
    public string Action { get; }

    public Privilege(string type, string accessType, string value, string action)
    {
        Type = type;
        AccessType = accessType;
        Value = value;
        Action = action;
    }
}

class Test
{
    static void Main()
    {
        var privileges = new List<Privilege>
        {
            // Bad: should cause an exception
            new Privilege("a", "a", "a", "a"),
            new Privilege("a", "a", "a", "b"),

            // Another bad one; let's check the
            // failure represents both
            new Privilege("x", "y", "z", "action1"),
            new Privilege("x", "y", "z", "action2"),

            // These have one property difference
            // in each case
            new Privilege("b", "a", "a", "a"),
            new Privilege("a", "b", "a", "a"),
            new Privilege("a", "a", "b", "a"),

            // Duplicate type/access/value, but same action too.
            new Privilege("d", "e", "f", "action"),
            new Privilege("d", "e", "f", "action")
        };
        CheckPrivileges(privileges);
    }

    static void CheckPrivileges(IEnumerable<Privilege> privileges)
    {
        var failures = privileges
            // Group the privileges by 3 properties, extracting actions as the values
            .GroupBy(p => new { p.Type, p.AccessType, p.Value }, p => p.Action)
            // Find any groups which have more than one distinct action
            .Where(g => g.Distinct().Skip(1).Any())
            .ToList();

        if (failures.Count > 0)
        {
            // There's at least one failure. There may be many. Throw
            // whatever exception you want here. This is just an example.
            var individualMessages =
                failures.Select(g => $"{g.Key}: {string.Join(", ", g.Distinct())}");
            throw new Exception(
                $"Invalid privilege combinations: {string.Join("; ", individualMessages)}");
        }
    }
}

Dies erzeugt eine Ausnahme wie diese (ich habe die Zeilenumbrüche hinzugefügt):

Unhandled Exception: System.Exception: Invalid privilege combinations:
{ Type = a, AccessType = a, Value = a }: a, b;
{ Type = x, AccessType = y, Value = z }: action1, action2
3
Jon Skeet 18 Apr. 2018 im 09:27
var duplicates = privilegecollection.GroupBy(x => new {x.Type, x.AccessType, x.Value})
                                    .Where(g => g.Count() > 1)
                                    .Select(g => g.Key);

Wenn die Anzahl duplicates größer als 0 ist, können Sie eine Ausnahme auslösen.

0
Navoneel Talukdar 18 Apr. 2018 im 09:20

Ich denke, die einfachste Lösung besteht darin, 2 Any() zu verwenden.

bool HasDoubleOtherAction = privilegeList.Any(outer => privilegeList
                               .Any(inner => outer.Type == inner.Type
                                             && outer.AccessType == inner.AccessType
                                             && outer.Value == inner.Value
                                             && outer.Action != inner.Action));
0
Chrᴉz says reinstate Monica 18 Apr. 2018 im 09:34