C# 通用和非通用接口及继承-访问时的歧义
我有以下设置C# 通用和非通用接口及继承-访问时的歧义,c#,generics,inheritance,C#,Generics,Inheritance,我有以下设置 基类 public class Fruit { } 继承类 public class Apple : Fruit { } 通用基接口 public interface IFruitsBase<T> where T : Fruit { T GetItem(); void ProcessItem(T fruit); void Check(); } 我的目标是,如果有人通过以下方式访问对象: var context = new Cont
- 基类
public class Fruit { }
- 继承类
public class Apple : Fruit { }
- 通用基接口
我的目标是,如果有人通过以下方式访问对象:public interface IFruitsBase<T> where T : Fruit { T GetItem(); void ProcessItem(T fruit); void Check(); }
如果有人通过以下方式访问它:var context = new Context(); context.Apples.[only apple relevant methods should be accessable]
无论是通过方法a还是方法b得到的,都应该可以通过签名为的方法var context = new Context(); context.GetFruits(item.GetType()).[only fruit relevant methods should be accessable]
void Foo(IFruits fruits);
在我看来,您的
是错误的。您不会基于泛型接口声明非泛型接口,而是以另一种方式进行声明。这样做更有意义 这就是我想到的:公共接口IFruits:IFruitsBase
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); }
在我看来,您的公共接口IFruitsBase,其中T:Fruit { T GetItem(); 无效处理项目(T水果); } 公共接口IFruits { 水果项目(); 无效加工项目(水果); 无效检查(); } 公共类水果:IFruitsBase,IFruits其中T:水果 { 公共T GetItem() { 返回null; } 公共物品(T水果) { } 公共作废检查() { } 水果IFruits.GetItem() { 抛出新的NotImplementedException(); } 无效IFruits.ProcessItem(水果) { 加工项目((T)水果); } } //从现在开始没有变化 公共类苹果:水果、苹果 { public void MakeAppleJuice(IEnumerable apples) { } } 公共级水果 { } 公营苹果:水果 { } 公共接口IApples:IFruitsBase、IFruits { void MakeAppleJuice(可数苹果); }
是错误的。您不会基于泛型接口声明非泛型接口,而是以另一种方式进行声明。这样做更有意义 这就是我想到的:公共界面IFruits:IFruitsBase
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); }
我认为,如果您将这里要做的事情解包,就会出现一个解决方案 首先,我不喜欢用复数类来表示列表。i、 e公共接口IFruitsBase,其中T:Fruit { T GetItem(); 无效处理项目(T水果); } 公共接口IFruits { 水果项目(); 无效加工项目(水果); 无效检查(); } 公共类水果:IFruitsBase,IFruits其中T:水果 { 公共T GetItem() { 返回null; } 公共物品(T水果) { } 公共作废检查() { } 水果IFruits.GetItem() { 抛出新的NotImplementedException(); } 无效IFruits.ProcessItem(水果) { 加工项目((T)水果); } } //从现在开始没有变化 公共类苹果:水果、苹果 { public void MakeAppleJuice(IEnumerable apples) { } } 公共级水果 { } 公营苹果:水果 { } 公共接口IApples:IFruitsBase、IFruits { void MakeAppleJuice(可数苹果); }
Apple Apples : List<Apple>
我想,如果你把你想做的事情拆开,一个解决方案就会出现 首先,我不喜欢用复数类来表示列表。i、 eApple Apples : List<Apple>
好吧,它不能实现你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 }
好吧,它不能实现你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 }
为了实现这一点,您需要构造一个协变接口。你有没有听说过,特别是?您需要将
重新定义为协变。即,在泛型参数上使用IFruitsBase
关键字,并将其约束为out
,如IFruit
首先为IFruitsBase,其中T:IFruit
和Fruit
类定义接口,并在实际类中实现它们:Apple
然后用复数(我希望这只是一个例子,对吗?)。IMHO您可以去掉非通用接口public interface IFruit { } public interface IApple : IFruit { } public class Fruit : IFruit { } public class Fruit : IFruit { } public class Apple : Fruit, IApple { }
,并将通用接口IFruits
重命名为IFruitsBase
。作为编码标准,可以将基后缀应用于要继承的类IFruits
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.Apples
方法才可用 您需要构造一个协变接口来实现这一点。你有没有听说过,特别是?您需要将makeappleguice()
重新定义为协变。即,在泛型参数上使用IFruitsBase
关键字,并将其约束为out
,如IFruit
首先为IFruitsBase,其中T:IFruit
和Fruit
类定义接口,并在实际类中实现它们:Apple
然后用复数(我希望这只是一个例子,对吗?)。IMHO您可以去掉非通用接口public interface IFruit { } public interface IApple : IFruit { } public class Fruit : IFruit { } public class Fruit : IFruit { } public class Apple : Fruit, IApple { }
,并将通用接口IFruits
重命名为IFruitsBase
。作为编码标准,可以将基后缀应用于要继承的类IFruits
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.Apples
方法才可用 我希望我没有看错这个问题,这也不是太愚蠢:)makeappleguice()
公共接口IFruit { } 公共接口应用:IFruit { } 公共接口IFruit,其中T:IFruit { T GetItem(); 无效处理项目(T水果); 无效检查(); } 公共类水果:IFruit其中T:IFruit { 公共作废检查() { 抛出新的NotImplementedException(); } 公共T GetItem() { 抛出新的NotImplementedException(); } 公共物品(T水果) { 抛出新的NotImplementedException(); } } 公共接口应用程序 { void MakeAppleJuice(可数苹果); } 公共类苹果:水果、苹果 { public void MakeAppleJuice(IEnumerable apples) { 抛出新的NotImplementedException(); } } 公共类上下文 { 公共IApples苹果{get;set;} 公共上下文() { 这个苹果=新苹果(); } 公共图书馆
public interface IApples : IFruits<Apple>
public class Fruits<T> : IFruits<T> where T : Fruit
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]
public interface IFruit { } public interface IApple : IFruit { } public class Fruit : IFruit { } public class Fruit : IFruit { } public class Apple : Fruit, IApple { }
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 } }
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>(); } }
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(); } }