10
votes

Existe-t-il une solution de contournement pour la contrainte de type générique de «classe spéciale» enum en C # 3.0?

mise à jour: strong> Voir le bas de cette question pour une solution de contexte C #. P>

salut là-bas, p>

Considérez la méthode d'extension suivante: P>

MyEnum e;
e.HasFlags(MyOtherEnum.DoFunkyStuff);


8 commentaires

Peut-être que cela n'a pas senti qu'une telle contrainte était nécessaire dans tous les cas très rares. Qui sait ... Je suis d'accord avec eux si c'était le cas :)


@Skurmedel: Ce qui est étrange, c'est qu'il est spécifiquement interdit ... En d'autres termes, la spécification a été faite plus compliquée pour restreindre. Je ne vois pas pourquoi. Peut-être que Eric Lippert expliquera :)


Oui, je suis d'accord avec Jon Skeet, bien que cela puisse être que cela ait été négligé (ils ont utilisé la même vérification de l'héritage des contraintes qu'ils font pour l'héritage de classe) ... mais je ne connais vraiment pas le fonctionnement intérieur de C #.


Eric Lippert a précédemment publié sur les contraintes de type ENum en C #: Stackoverflow.com/Questtions/1331739/Enum-type-constraintS-in -C / ...


Je vois. Puis-je le prendre de sa réponse que même s'il y avait eu une option pour éteindre l'erreur du compilateur, le code ne fonctionnerait toujours pas? Sauf si c'est le cas, je ne vois pas pourquoi cette limitation est forcée sur moi (il serait agréable de pouvoir désactiver explicitement l'erreur CS0702.)


J'ai écrit une bibliothèque C ++ / CLI pour la fonctionnalité que je voulais et cela a bien fonctionné. Cela me conduit à croire qu'il devrait être possible de faire en C # aussi ... mais je suppose que nous ne verrons pas cela que c # 5.0 Même si les concepteurs peuvent être convaincus de le permettre? (Je voterais toujours pour un commutateur de compilateur pour désactiver l'erreur CS0702 si ... mais peut-être que ce n'est pas possible.)


Aucune raison de voter pour fermer ceci ... J'ai spécifiquement mentionné toutes les solutions fournies à votre question ici, de sorte que seules d'autres solutions soient fournies, et nous avons maintenant la bibliothèque de Jon sur le chemin ainsi que la solution C ++ / CLI . Votre question était d'un an et je ne cherchais aucune des réponses qu'elle avait.


Assez juste - si vous n'aviez pas ré-demandé cela, nous n'aurions probablement pas eu l'activité récente. C'est fondamentalement la même question cependant. Ainsi +1 et un vote pour fermer comme Dupe; p


4 Réponses :


10
votes

EDIT: Une bibliothèque est maintenant disponible en supportant cette via ilasm / ilasm: Non contraint de la société .


Les membres de l'équipe C # ont précédemment indiqué qu'ils étaient comme em> pour pouvoir prendre en charge où T: Enum code> et où T: Déléguer , mais qu'il n'a jamais été une priorité assez élevée. (Je ne suis pas sûr de ce que le raisonnement est d'avoir la restriction de la première place, certes ...) p>

La solution de contournement la plus pratique en C # est la suivante: P>

public static bool HasFlags<T>(this T value, T flags) where T : struct
{
    if (!(value is Enum))
    {
        throw new ArgumentException();
    }
    return EnumHelper<T>.HasFlags(value, flags);
}

private class EnumHelper<T> where T : struct
{
    static EnumHelper()
    {
        if (!typeof(Enum).IsAssignableFrom(typeof(T))
        {
            throw new InvalidOperationException(); // Or something similar
        }
    }

    internal static HasFlags(T value, T flags)
    {
        ...
    }
}


13 commentaires

Je pense qu'il est important de conserver des méthodes de vulgarisation limitées dans une portée limitée et je n'utiliserai donc pas où T: struct en raison des raisons mentionnées dans ma question ( 123.HasFlags (456) Compilerait bien.) Je ressemble à la solution de Geco, mais je ne peux pas justifier de créer une bibliothèque entière pour une méthode. Est-il possible de configurer un processus pour "injecter" le C ++ / CLI dans une bibliothèque C # lors de la compilation?


@BlixT: Eh bien, vous pourriez examiner la réécriture binaire, mais cela va probablement être laid. Je me demande s'il y aurait intérêt à un projet open source pour un tas de "choses utiles que l'on puisse faire avec des délégués et des énumissements" ...


Ok, je ne le ferais que s'il y avait une façon "facile" de le faire =) et oui, à en juger par les discussions que j'ai trouvées sur Google, ce problème n'est pas tout ce qui est rare, Et j'apprécierais certainement une telle bibliothèque.


Ok, va le considérer. Je devrais trouver des développeurs compétents C ++ / CLI si ... mon C ++ est affreux :) Une autre alternative peut être d'écrire le code en C # avec des marqueurs spéciaux et de réécrire binaire sur la bibliothèque pour modifier les contraintes. Hmm.


Nice =) ouais, une fois, je commençais à avoir la suspension de C ++, puis de venir comme Python et C # et m'as gâté!


Jetez un coup d'œil à ma réponse à cette question pour le code C ++ / CLI qui implémente la fonctionnalité HASFLAGS que je cherchais.


Vous pouvez utiliser ilmmerge ( recherche.microsoft.com/en-us/people /mbarnett/ilmerge.aspx ) Pour inclure ce qui serait un assez vestigial C ++ / CLI assemblé dans votre code principal.


Intéressant! Merci pour le lien =)


J'accepte cette réponse car elle conduit à la seule solution C # viable que j'ai vue. La réponse de GRECO est toujours une très belle solution, cependant.


@Blixy: ont édité le lien de la bibliothèque dans la réponse ...


N'oubliez pas que vous voulez : Enum , pas : Enum , pour distinguer s'il faut autoriser le passage system.enum


Le blog MSDN de Jon Skeet a changé de jon_skeet à Jonskeet .. Donc, l'URL correcte pour le billet de blog est maintenant: blogs.msmvps.com/jonskeet/2009/09/10/...


@Ynngvar: Eh bien, c'est maintenant CodeBlog.jonskeet.uk, donc: CodeBlog.jonskeet.uk/2009/09/10/...



2
votes

Je ne pouvais pas résister à un déplacement au travail de C ++, et puisque je l'ai eu pour travailler, je pensais que je le partageais le reste de ya!

Voici le code C ++ (mon C ++ est très Rusty alors veuillez indiquer les erreurs, en particulier comment les arguments sont définis): p> xxx pré>

et le code C # pour le test (application de la console): P>

using System;
using Blixt.Utilities;

namespace Blixt.Playground
{
    [Flags]
    public enum Colors : byte
    {
        Black = 0,
        Red = 1,
        Green = 2,
        Blue = 4
    }

    [Flags]
    public enum Tastes : byte
    {
        Nothing = 0,
        Sour = 1,
        Sweet = 2,
        Bitter = 4,
        Salty = 8
    }

    class Program
    {
        static void Main(string[] args)
        {
            Colors c = Colors.Blue | Colors.Red;
            Console.WriteLine("Green and blue? {0}", c.HasFlags(Colors.Green | Colors.Red));
            Console.WriteLine("Blue?           {0}", c.HasFlags(Colors.Blue));
            Console.WriteLine("Green?          {0}", c.HasFlags(Colors.Green));
            Console.WriteLine("Red and blue?   {0}", c.HasFlags(Colors.Red | Colors.Blue));

            // Compilation error:
            //Console.WriteLine("Sour?           {0}", c.HasFlags(Tastes.Sour));

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey(true);
        }
    }
}


0 commentaires

3
votes

En fait, c'est possible, avec une tour laide. Cependant, il ne peut pas être utilisé pour les méthodes d'extension.

public abstract class Enums<Temp> where Temp : class {
    public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp {
        return (TEnum)Enum.Parse(typeof(TEnum), name); 
    }
}
public abstract class Enums : Enums<Enum> { }

Enums.Parse<DateTimeKind>("Local")


1 commentaires

FYI A VERS VB.NET de cet excellent, si laid, astuce.



1
votes

Vous pouvez atteindre cet objectif en utilisant il tissage et Extractraint

vous permet d'écrire Ce code xxx

Ce qui est compilé xxx


0 commentaires