我有以下设置
基类
public class Fruit
{
}
继承类
public class Apple : Fruit
{
}
通用基本界面
public interface IFruitsBase<T> where T : Fruit
{
T GetItem();
void ProcessItem(T fruit);
void Check();
}
非泛型接口,它继承自基类的泛型接口作为泛型
public interface IFruits : IFruitsBase<Fruit>
{
}
相应类的具体接口
public interface IApples : IFruitsBase<Apple>, IFruits
{
void MakeAppleJuice(IEnumerable<Apple> apples);
}
基础实施类
public class Fruits<T> : IFruitsBase<T>, IFruits where T : Fruit
{
public T GetItem()
{
return null;
}
public void ProcessItem(T fruit)
{
}
public void Check()
{
}
Fruit IFruitsBase<Fruit>.GetItem()
{
return this.GetItem();
}
void IFruitsBase<Fruit>.ProcessItem(Fruit fruit)
{
ProcessItem((T)fruit);
}
}
具体实施
public class Apples : Fruits<Apple>, IApples
{
public void MakeAppleJuice(IEnumerable<Apple> apples)
{
}
}
我面临的问题是:
public interface IApples : IFruitsBase<Apple>, IFruits
{
void MakeAppleJuice(IEnumerable<Apple> apples);
}
我收到的消息是:
通过此界面
访问时可能存在歧义Apple IFruitsBase<Apple> Get()
Fruit IFruitsBase<Fruit>.Get()
要解决此问题,我可以从IFruits
删除界面IApples
,但这会产生其他错误,如下所示:
public class Context
{
public IApples Apples { get; set; }
public Context()
{
this.Apples = new Apples();
}
public IFruits GetFruits(Type type)
{
return this.Apples; //simplified the code here, it should actually get the member of this that fits the type
}
}
public class Foo
{
public void Main()
{
var context = new Context();
Check(new IFruits[] { context.Apples }); //can't do that since context.Apples doesnt inherit from IFruits, to fix the above ambiguity
}
public void Check(IEnumerable<IFruits> fruits)
{
foreach (var fruit in fruits)
fruit.Check();
}
}
我的目标是,如果有人通过以下方式访问对象:
var context = new Context();
context.Apples.[only apple relevant methods should be accessable]
如果有人通过以下方式访问它:
var context = new Context();
context.GetFruits(item.GetType()).[only fruit relevant methods should be accessable]
无论是否用方法a或b得到它,都应该可以通过签名为
的方法void Foo(IFruits fruits);
答案 0 :(得分:1)
嗯,它没有100%完成你的愿望(因为它似乎很难完成),但它应该可以解决问题。
public interface IFruits
{
Fruit GetItem();
void ProcessItem(Fruit fruit);
void Check();
}
// I changed the name of your IFruitsBase, because it's the same thing as IFruits
// No need to have 2 differents names to name the same thing
public interface IFruits<T> : IFruits where T : Fruit
{
T GetItem();
void ProcessItem(T fruit);
void Check(); // This one could probably be removed from this interface
}
然后:
public interface IApples : IFruits<Apple>
和
public class Fruits<T> : IFruits<T> where T : Fruit
现在,IFruits继承自IFruits,所以没有更多的冲突,因为你不会实现两次相同的接口。
所以,如果你这样做:
var context = new Context();
context.Apples.[You will have access to both IFruits and IFruits<Apple>]
用这个:
var context = new Context();
context.GetFruits(item.GetType()).[only IFruits methods are accessable]
答案 1 :(得分:1)
您需要构建一个协变接口才能实现此目的。您是否听说过variance in C#和variant interfaces?您需要将IFruitsBase<T>
重新定义为协变。即,在泛型参数上使用out
关键字并将其约束为IFruit
,如此IFruitsBase<out T> where T : IFruit
首先定义Fruit
和Apple
类的接口,然后在实际的类中实现它们:
public interface IFruit
{
}
public interface IApple : IFruit
{
}
public class Fruit : IFruit
{
}
public class Fruit : IFruit
{
}
public class Apple : Fruit, IApple
{
}
然后使用复数形式(我希望这仅仅是为了示例,对吧?)。恕我直言,您可以摆脱非通用接口IFruits
并将通用IFruitsBase<T>
重命名为IFruits<T>
。作为编码标准,您将 Base 后缀应用于要继承的类。
public interface IFruits<out T> where T : IFruit
{
T GetItem();
void ProcessItem(IFruit fruit);
void Check();
}
public interface IApples : IFruits<IApple>
{
void MakeAppleJuice(IEnumerable<IApple> apples);
}
public class Fruits<T> : IFruits<T> where T : IFruit
{
public void Check()
{
throw new NotImplementedException();
}
public T GetItem()
{
throw new NotImplementedException();
}
public void ProcessItem(IFruit fruit)
{
if (fruit is T)
{
}
else
{
throw new NotSupportedException();
}
}
}
public class Apples : Fruits<IApple>, IApples
{
public void MakeAppleJuice(IEnumerable<IApple> apples)
{
// Do the juice
}
}
然后稍微修改Context
类:
public class Context
{
public IApples Apples { get; set; }
public IBananas Bananas { get; set; }
public Context()
{
Apples = new Apples();
}
public IFruits<T> GetFruits<T>() where T : IFruit
{
return new Fruits<T>();
}
}
现在MakeAppleJuice()
方法仅在您访问context.Apples
时可用。
答案 2 :(得分:1)
我希望我不明白这个问题是错的,这不是太愚蠢:)
public interface IFruit
{
}
public interface IApple: IFruit
{
}
public interface IFruits<T> where T : IFruit
{
T GetItem();
void ProcessItem(T fruit);
void Check();
}
public class Fruits<T> : IFruits<T> where T : IFruit
{
public void Check()
{
throw new NotImplementedException();
}
public T GetItem()
{
throw new NotImplementedException();
}
public void ProcessItem(T fruit)
{
throw new NotImplementedException();
}
}
public interface IApples
{
void MakeAppleJuice(IEnumerable<IApple> apples);
}
public class Apples : Fruits<IApple>, IApples
{
public void MakeAppleJuice(IEnumerable<IApple> apples)
{
throw new NotImplementedException();
}
}
public class Context
{
public IApples Apples { get; set; }
public Context()
{
this.Apples = new Apples();
}
public IFruits<IFruit> GetFruits<T>()
{
return null;
}
private void test()
{
//this.GetFruits<IFruit>().ProcessItem(
//this.GetFruits<IApple>().ProcessItem(
//this.Apples.MakeAppleJuice(
}
}
public class Foo
{
public void Main()
{
var context = new Context();
Check(new IFruits<IFruit>[] { context.GetFruits<IApple>() });
}
public void Check(IEnumerable<IFruits<IFruit>> fruits)
{
foreach (var fruit in fruits)
fruit.Check();
}
}
答案 3 :(得分:0)
在我看来,你的public interface IFruits : IFruitsBase<Fruit>
是错误的。您没有基于通用接口声明非泛型接口,而是以相反的方式执行。这样更有意义。
这就是我的想法:
public interface IFruitsBase<T> where T : Fruit
{
T GetItem();
void ProcessItem(T fruit);
}
public interface IFruits
{
Fruit GetItem();
void ProcessItem(Fruit fruit);
void Check();
}
public class Fruits<T> : IFruitsBase<T>, IFruits where T : Fruit
{
public T GetItem()
{
return null;
}
public void ProcessItem(T fruit)
{
}
public void Check()
{
}
Fruit IFruits.GetItem()
{
throw new NotImplementedException();
}
void IFruits.ProcessItem(Fruit fruit)
{
ProcessItem((T)fruit);
}
}
// no changes from here on
public class Apples : Fruits<Apple>, IApples
{
public void MakeAppleJuice(IEnumerable<Apple> apples)
{
}
}
public class Fruit
{
}
public class Apple : Fruit
{
}
public interface IApples : IFruitsBase<Apple>, IFruits
{
void MakeAppleJuice(IEnumerable<Apple> apples);
}
答案 4 :(得分:0)
我认为如果你解开你在这里尝试做的事情,就会出现一个解决方案。
首先,我不喜欢使用复数类来表示列表。即
Apple
Apples : List<Apple>
这不完全是你在做什么,但它基本上是一回事。 IMO这样做会增加维护代码的难度,并且会掩盖您尝试做的事情。相反,我已使用Apple
我也拿出了我没有使用的所有东西,所以我可能错过了一些东西,但我试图把你想要的一切都包括在内。这就是我根据你所拥有的东西。
public class Context
{
public Apple[] Apples { get; set; }
public IFruit[] GetFruits()
{
return null;
}
}
public interface IFruit
{
}
public class Apple : IFruit
{
}
public class Banana : IFruit
{
}
public static class Apples
{
public static void MakeAppleJuice(this Apple[] apples)
{
}
public static void ProcessItem(this Apple[] apples, Apple fruit)
{
}
}
class Program
{
static void Foo(IFruit[] fruits)
{
}
static void Main(string[] args)
{
var context = new Context();
context.Apples.MakeAppleJuice();
context.GetFruits();
Foo(context.Apples); //Dangerous call, but legal.
Foo(context.GetFruits());
context.Apples.ProcessItem(new Banana()); // Does not compile.
}
}