javirs
javirs

Reputation: 1100

create a base item that has a dynamic enum as a field

I have different types of item. Each of them has a enum where ID's are keept. I want my base class to have a method to check if the item's ID is on a given list. Something like:

abstract class Thing
{
   public string Name;
   public int Amount;
   //others
   abstract bool IsInList(list<xxxxx> list);
   abstract xxxxxxx ID;
}

class Fruit : Thing
{
   public IDs = {F_NotSet, F_Banana, F_Apple, ...}
   public IDs ID = IDs.F_NotSet;
   public bool IsInList(List<T> list) //this wont compile
   {
      if(typeof(T) == typeof(IDs))
          return list.Contains(IDs);
      else
          return false;
   }
}

The thing is that I also have a (blazor) UI component that visualizes things so I want to be able to do my

<div>@Thing.Name [@Thing.Amount]</div>
<code>
   [Parameter] public Thing Thing {get;set;}
</code>

And use it on my page for all kind of things, like :

<div>
@foreach(var thing in Things) //things being List<Thing>
{
   <ThingViewer ItemToShow=thing/>
}
</div>

That's why I don't want to go the Thin<T>path because then my UI component to visualize Things and my page gets messy.

On the other side, I would like to use this "IsInList" method from the page to do things like

<div>
@foreach(var thing in MyThings) //MyThings being List<Thing>
{
   @if(thing.IsInList(ThingsInOffer))
   {
      <div class="offer">
        <ThingsVisualizer ItemToShow=thing/>
      </div>
   }
}
</div>

Upvotes: 1

Views: 91

Answers (1)

Fildor
Fildor

Reputation: 16104

Here is the complete working example from fiddle, that helped solve the issue:

using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Collections.Generic;
                    
public class Program
{
    // Just for showcasing:
    public static void Main()
    {
        var apple = new Fruit(Fruits.Apple);
        var banana = new Fruit(Fruits.Banana);
        var orange = new Fruit(Fruits.Orange);
        var strawberry = new Nut(Nuts.Strawberry);
        
        var assortedFruits = new []{ Fruits.Apple, Fruits.Orange };
        
        Console.WriteLine("I ({0}) am {1}an assorted fruit!", apple.Id, apple.IsInList(assortedFruits)?"":"not ");
        Console.WriteLine("I ({0}) am {1}an assorted fruit!", banana.Id, banana.IsInList(assortedFruits)?"":"not ");
        Console.WriteLine("I ({0}) am {1}an assorted fruit!", strawberry.Id, strawberry.IsInList(assortedFruits)?"":"not ");
        
        PrintDetails(apple);
        PrintDetails(banana);
        PrintDetails(orange);
        PrintDetails(strawberry);
        
        foreach( var thing in new IThing[]{apple, strawberry} )
        {
            Console.WriteLine($"{thing.Name}s have {thing.SomeProperty}");
        }
    }
    
    public static void PrintDetails(IThing thing)
    {
        // Going by an interface: We do not really care, what kind of 
        // "thing" it is in particular.
        thing.Print();
    }
}

// Two "Kinds" of Things: Fruits and Nuts

public enum Fruits
{
    Apple,
    Banana,
    Orange
}

public enum Nuts
{
    Strawberry
}

// Things all kinds of "Things" need to be able to do:

public interface IThing
{
    void Print();
    string Name {get;}
    string SomeProperty {get;}
}

// Common generic implementations:
public abstract class Thing<TIdentifyingThing> : IThing
{
    protected TIdentifyingThing _me;
    
    protected Thing(TIdentifyingThing id)
    {
        _me = id;
    }
    
    public TIdentifyingThing Id => _me;
    public string Name => _me.ToString();
    public abstract string SomeProperty {get;}

    // I think the "thing" here was that you can have generic methods
    // with Types that do not need to be the same as the generic class's
    // type. Here `T` versus `TIdentifyingThing`.
    public bool IsInList<T> (IEnumerable<T> list)
    {
        if( typeof(T) != typeof(TIdentifyingThing) ) return false;
        if( list is not null && list.Any() )
        {
            return list.Cast<TIdentifyingThing>().Contains(_me);
        }
        return false;
    }
    
    public abstract void Print();
}

// The specific Things:

public class Fruit : Thing<Fruits>
{
    public Fruit( Fruits identity ): base(identity) {}
    
    public override string SomeProperty => "just some property.";
    
    public override void Print()
    {
        Console.WriteLine($"My fruity details are: I am a{(Id.ToString().StartsWithVocal() ? "n" : "" )} {Id}.");
    }
}

public class Nut : Thing<Nuts>
{
    public Nut( Nuts identity ): base(identity) {}
    
    public override string SomeProperty => "not always the appearance you expect.";
    
    public override void Print()
    {
        Console.WriteLine($"My nutty details are: I am a{(Id.ToString().StartsWithVocal() ? "n" : "" )} {Id}.");
    }
}


// Just so the code is complete. Doesn't actually contribute to the solution as such.
public static class StringExtensions
{
    public static bool StartsWithVocal(this string me)
    {
        return Regex.IsMatch(me, "^[aeiouAEIOU]");
    }
}

Upvotes: 1

Related Questions