创建一个以动态枚举作为字段的基项



我有不同类型的项目。它们每个都有一个枚举,其中保存ID。我希望我的基类有一个方法来检查项目的ID是否在给定的列表上。比如:

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;
}
}

问题是,我也有一个(blazor) UI组件可视化的东西所以我想能够做我的

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

并在我的页面上使用它,例如:

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

这就是为什么我不想去Thin<T>路径,因为这样我的UI组件可视化的东西和我的页面变得混乱。

另一方面,我想使用这个"IsInList"方法来执行诸如

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

下面是来自fiddle的完整工作示例,它帮助解决了这个问题:

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]");
}
}

相关内容

最新更新