这是一个城市建设者游戏,但框架应该是有用的任何请求和发送。基本上,你有供应商和请求者。当请求者的需求不足时,就会提交请求。然后,每一个滴答,所有的请求都被处理,适当的供应商将他们的东西发送给适当的请求者,每个人都很高兴。我想做的是用仿制药来完成这一切。我对泛型相当在行,但已经有一段时间没有使用它们了,所以解决方案可能很简单。以下是一些代码:
public interface Requester<T> where T : Item
{
bool NeedsToRequest();
Request<T> LodgeRequest();
}
public interface Supplier<T> where T : Item
{
void Supply(Request<T> request);
}
public class Request<T> where T : Item
{
public Pile<T> Target;
public int Amount;
}所有这些都集中在一个大型中介类中,该类处理请求的生成和实现等。
public abstract class ProductionHandler
{
public List<Supplier<Item>> Suppliers;
public List<Request<Item>> Requests;
public abstract bool TryRequest<T>(Request<T> request) where T : Item
}同样相关的还有:
public class Pile<T> : List<T> where T : Item
{
public int Amount
{
get { return this.Count; }
}
}最大的问题是按照T的类型对供应商进行排序,我想要查看请求的列表,获取它的类型,从列表中找到匹配的供应商类型,然后处理请求。另一个问题是,让你说你有“花:项目”和“玫瑰:花”和“向日葵:花”。如果有些东西需要鲜花,那么您可能希望将其发送到任意类型,因此,在这种情况下,仅仅比较类型就不那么容易了。如果有人能把我和一篇好文章联系起来,或者建议我如何安排一切,那就太好了,谢谢。
发布于 2017-05-22 08:59:30
在行中可以帮助进一步的第一步是使用方差,这样就可以将Supplier<Rose>转换为Supplier<Flower>和Supplier<Item> (反之亦然)。如果不是这样,供应商必须是一个接口(ISupplier<out T> )。更多信息在这里:广义协方差与反方差
这样,您可以保留一个ISupplier<Item>列表,但要确保供应商是强类型的。这意味着列表只包含具有集合可转换的ISupplier<Rose>或ISupplier<Sunflower>等项的直接实现,您可以简单地使用OfType<ISupplier<ItemType>>获取所需的供应商。
为了耦合请求,有几种可能性(例如在ISupplier上有2种类型,或者让接口与另一种类型公开另一种通用方法,并让供应商按添加的类型进行检查),但最干净的方法是为请求(IRequest<in T> )使用一个相反的接口,这可以在接口定义中使用。
示例设置:
public interface ISupplier<out T>
{
int Supply(IRequest<T> request);
}
public interface IRequest<in T> //request is input and is contravariant so it can be used in the ISupplier definition. Roughly said it means that if a specific type is used, it can also be used as input for any child type
{
int Amount{get;set;}
}
public abstract class ProductionHandlerBase
{
public List<ISupplier<Item>> Suppliers = new List<ISupplier<Item>>(); //ISupplier is covariant so any more derrived type (than Item) is still valid
public IEnumerable<ISupplier<T>> GetSuppliers<T>() //helper function to make calls easier, but Suppliers could be used directly as well
{
return Suppliers.OfType<ISupplier<T>>();
}
public bool TryRequest<T>(IRequest<T> Request)
where T:Item
{
//example implementation. (neither optimized or necessariy logical, but it does show the expected types are used)
foreach(var sup in GetSuppliers<T>())
{
if(sup.Supply(Request) > 0 && Request.Amount == 0)
return true;
}
return false;
}
public void TestOutput()
{
Console.WriteLine(string.Join(", ", Suppliers));
}
}
class ProductionHandlerExample:ProductionHandlerBase{}
public class Request<T>:IRequest<T>{
public int Amount{get;set;}
}
public abstract class Supplier<T>:ISupplier<T>{
int pileAmount = 4; //just to have an example
public int Supply(IRequest<T> request) //example implementation
{
int cnt = Math.Min(request.Amount, pileAmount);
if(cnt==0)return 0;
pileAmount -= cnt;
request.Amount -=cnt;
return cnt;
}
public override string ToString() {return $"{typeof(T).Name}(s): {pileAmount}"; }
}
//items
public abstract class Item{}
public abstract class Flower:Item{}
public class Rose:Flower{}
public class SunFlower:Flower{}
public class Car:Item{}
//suppliers
public class Florist:Supplier<Flower>{} //implementation can still be on a class, as long as the collections are based on the covariant interface
public class Rosy:Supplier<Rose>{}
public class CarDealer:Supplier<Car>{}示例用法:
var p = new ProductionHandlerExample();
p.Suppliers.Add(new Florist());
p.Suppliers.Add(new Rosy());
p.Suppliers.Add(new CarDealer());
//p.GetSuppliers<Flower>() -> Florist, Rosy
//p.GetSuppliers<Rose>() -> Rosy
//p.GetSuppliers<Item>() -> all items (Florist, Rosy, CarDealer)
//in the example setup, each supplier has a pile of 4
p.TestOutput(); //Flower(s): 4, Rose(s): 4, Car(s): 4
p.TryRequest(new Request<Rose>{Amount = 2}); //returns true
p.TestOutput(); //Flower(s): 4, Rose(s): 2, Car(s): 4
p.TryRequest(new Request<Car>{Amount = 5}); //returns false, there are only 4 cars
p.TestOutput(); //Flower(s): 4, Rose(s): 2, Car(s): 0
p.TryRequest(new Request<Flower>{Amount = 5}); //returns true, stock of both florist and Roses are used
p.TestOutput(); //Flower(s): 0, Rose(s): 1, Car(s): 0在本例实现中,不执行子类型检查。如果花店里的花可能是玫瑰。这是因为该示例假定花的类型实际上并不为人所知。如果它是已知的,最好有一个通用的(I)Supplier和一个通用的TryRequest方法,其中每个实现检查自己的股票(Pile.OfType<>或类似的)。
发布于 2017-05-22 08:41:07
我认为这与您的TryRequest方法有关。在您的TryRequest<T>(Request<T> request) where T : Item实现中,您有T,所以您可以很容易地使用反射通过Suppliers:
var supplier = Suppliers.FirstOrDefault
( sup => sup.GetType()
.GenericTypeArguments[0] == typeof(T)
);正如你所看到的,这不是很漂亮,但我现在没有更好的选择。
https://stackoverflow.com/questions/44108168
复制相似问题