Simulating polymorphic / general enumerations - C #

I know this is a strange name, and I know that inheritance is not possible with enumerations, so let me explain.

If I have the following classes:

  • Fruit (abstract)
    • Apple (concrete - derived from fruit)
    • Orange (concrete - derived from fruit)

And I have the following method implemented with generics:

public ICollection<T> FindFruit<T>() where T : Fruit
{
   return _fruitRepository
             .Fruits
             .OfType<T>()
             .ToList();
}

And I use it as follows:

var apples = _fruitServices.FindFruit<Apple>();

All perfectly.

Now I have the following enumeration:

public enum FruitAssociations
{
   Color,
   Manufacturers
}

Basically, Fruits can have many associations that determine which associations to include in the result from my repository.

So the method FindFruitabove looks something like this:

public ICollection<T> FindFruit<T>(FruitAssociations[] assocs) where T : Fruit
{
   return _fruitRepository
             .Fruits
             .OfType<T>()
             .IncludeAssocs(assocs) // ObjectQuery<Fruit> extension method.
             .ToList();
}

Here is this extension method:

public static ObjectQuery<Fruit> IncludeAssocs(this ObjectQuery<Fruit> source, FruitAssociations[] assocs)
{
   if (assocs.Contains(FruitAssociations.Color))
      query = query.Include("Color");
   // etc      
}

Also works great. The problem that I am facing right now is to have associations with a particular Fruit.

eg

public enum OrangeAssociations
{
   OrangeFamilies
}

, FindFruit, , T.

, :

var oranges = _fruitServices.FindFruit<Orange>(new[] { OrangeAssociations.OrangeFamilies });
var apples = _fruitServices.FindFruit<Apple>(new[] { AppleAssociations.AppleFamilies });

, , FindFruit , , T.

, , , Entity Framework 4 , , .Include ( , ). , , , , .Include.

, , :

public ICollection<T> FindFruit<T>(FruitAssociations<T> assocs) where T : Fruit

:

var associations = new FruitAssociations<Orange>(OrangeAssociations.OrangeFamilies);
var apples = _fruitServices.FindFruit<Apple>(associations);

, .

, /.

+3
3

, .

:

// finds fruits of type Orange, includes Color and OrangeFamilies
var result = FindFruit(OrangeAssociation.Color,
                       OrangeAssociation.OrangeFamilies);

// finds fruits of type Fruit, includes Manufacturers
var result = FindFruit(FruitAssociation.Manufacturers);

:

static ICollection<TFruit> FindFruit<TAssoc, TFruit>(
    params FruitAssociation<TAssoc, TFruit>[] assocs)
    where TAssoc : FruitAssociation<TAssoc, TFruit>, new()
    where TFruit : Fruit
{
    var query = _fruitRepository.Fruits.OfType<TFruit>();

    foreach (var assoc in assocs)
    {
        query = query.Include(assoc.Name);
    }

    return query.ToList();
}

abstract class FruitAssociation<TAssoc, TFruit>
    where TAssoc : FruitAssociation<TAssoc, TFruit>, new()
    where TFruit : Fruit
{
    public static readonly TAssoc Color = Define("Color");

    public static readonly TAssoc Manufacturers = Define("Manufacturers");

    protected static TAssoc Define(string name)
    {
        return new TAssoc { Name = name };
    }

    public string Name
    {
        get;
        private set;
    }
}

sealed class FruitAssociation : FruitAssociation<FruitAssociation, Fruit>
{
}

sealed class OrangeAssociation : FruitAssociation<OrangeAssociation, Orange>
{
    public static readonly OrangeAssociation OrangeFamilies =
        Define("OrangeFamilies");
}
+4

, Enum Generics . - :

public static ObjectQuery<Fruit> IncludeAssocs(
    this ObjectQuery<Fruit> source, Enum[] assocs) 
{
    foreach(var assoc in assocs)
    {
        query = query.Include(assoc.ToAssociationQueryString());
    }
}

, AssociationQueryString, :

public enum OrangeAssociations
{
    [AssociationQueryString("Orange Families")]
    OrangeFamilies
}

:

public class AssociationQueryStringAttribute : System.Attribute
{
    private readonly string value;
    public string Value { get { return this.value; } }

    public AssociationQueryStringAttribute(string value)
    {
        this.value = value;
    }
}

.ToAssociationQueryString(), :

public string ToAssociationQueryString(this Enum value)
{
    FieldInfo fi = value.GetType().GetField(value.ToString());
    AssociationQueryStringAttribute[] attributes = 
        (AssociationQueryStringAttribute[])fi.GetCustomAttributes(
            typeof(AssociationQueryStringAttribute), false);
    if (attributes.Length > 0)
    {
        return attributes[0].Value;
    }
    else
    {
        throw new InvalidOperationException(
            "Must use an enum decorated with the AssociationQueryString attribute.");
    }
}
+2

Enumerations are not as magical as everyone suggests. This is just a type with a bunch of readonly static fields and a private constructor. If you want inheritance to use a regular class and public static fields or properties that return instances of the class with the values ​​you want.

Example from another question

0
source

Source: https://habr.com/ru/post/1779307/


All Articles