我写了这个扩展方法(编译):
public static IEnumerable<J> Flatten<T, J>(this IEnumerable<T> @this)
where T : IEnumerable<J>
{
foreach (T t in @this)
foreach (J j in t)
yield return j;
}
Run Code Online (Sandbox Code Playgroud)
下面的代码导致编译时错误(找不到合适的方法),为什么?:
IEnumerable<IEnumerable<int>> foo = new int[2][];
var bar = foo.Flatten();
Run Code Online (Sandbox Code Playgroud)
如果我实现如下扩展,我没有编译时错误:
public static IEnumerable<J> Flatten<J>(this IEnumerable<IEnumerable<J>> @this)
{
foreach (IEnumerable<J> js in @this)
foreach (J j in js)
yield return j;
}
Run Code Online (Sandbox Code Playgroud)
编辑(2):我考虑回答这个问题,但它提出了另一个关于重载决策和类型约束的问题.我在这里提出这个问题:为什么类型约束不是方法签名的一部分?
我怀疑这里曾经问过(并回答过),但我不知道如何命名问题.为什么只有在我没有通过课程本身时才能表达通配符而没有问题?
这一切都归结为这段代码.一切都按预期工作,除了调用genericsHell(ShapeSaver.class):
interface Shape { }
interface Circle extends Shape { }
interface ShapeProcessor<T extends Shape> { }
class CircleDrawer implements ShapeProcessor<Circle> { }
class ShapeSaver<T extends Shape> implements ShapeProcessor<T> { }
class Test {
void genericsHeaven(ShapeProcessor<? extends Shape> a) {}
void genericsHell(Class<? extends ShapeProcessor<? extends Shape>> a) {}
void test() {
genericsHeaven(new CircleDrawer());
genericsHeaven(new ShapeSaver<Circle>());
genericsHell(CircleDrawer.class);
genericsHell(ShapeSaver.class); // ERROR: The method genericsHell is not applicable for the arguments (Class<ShapeSaver>)
}
}
Run Code Online (Sandbox Code Playgroud) 当我遇到一个我不理解的类型推断错误时,我正在玩一个爱好项目.我把它简化为以下简单的例子.
我有以下类和函数:
class Foo { }
class Bar { }
class Baz { }
static T2 F<T1, T2>(Func<T1, T2> f) { return default(T2); }
static T3 G<T1, T2, T3>(Func<T1, Func<T2, T3>> f) { return default(T3); }
Run Code Online (Sandbox Code Playgroud)
现在考虑以下示例:
// 1. F with explicit type arguments - Fine
F<Foo, Bar>(x => new Bar());
// 2. F with implicit type arguments - Also fine, compiler infers <Foo, Bar>
F((Foo x) => new Bar());
// 3. G with explicit type arguments - Still fine... …Run Code Online (Sandbox Code Playgroud) 鉴于以下课程......
public abstract class FooBase<TBar> where TBar : BarBase{}
public abstract class BarBase{}
public class Bar1 : BarBase{}
public class Foo1 : FooBase<Bar1> {}
Run Code Online (Sandbox Code Playgroud)
......以及以下方法......
public TBar DoSomething<TFoo, TBar>(TFoo theFoo)
where TFoo : FooBase<TBar>
where TBar : BarBase
{
return default(TBar);
}
Run Code Online (Sandbox Code Playgroud)
为什么以下代码行不能表示返回类型?
Bar1 myBar = DoSomething(new Foo1());
Run Code Online (Sandbox Code Playgroud)
相反,我必须指定像这样的泛型类型......
Bar1 myBar = DoSomething<Foo1, Bar1>(new Foo1());
Run Code Online (Sandbox Code Playgroud) 在以下示例中:
public static void main(String[] args) {
List<String> b = new ArrayList<String>();
first(b);
second(b);
List<List<String>> a = new ArrayList<List<String>>();
third(a);
fourth(a); // doesnt work
}
private static <T> void first(List<T> a){
System.out.println("List of T");
}
private static void second(List<?> a){
System.out.println("List of anything ");
}
private static <T> void third(List<List<T>> a){
System.out.println("List of a List of T ");
}
private static void fourth(List<List<?>> a){
System.out.println("List of a List of anything ");
}
Run Code Online (Sandbox Code Playgroud)
为什么第二个(b)的呼叫有效,但第四个(a)的呼叫不起作用?
我收到以下错误:
The method fourth(List<List<?>>) in the …Run Code Online (Sandbox Code Playgroud) 我有以下类/接口:
// Model
public class A : IA { }
// ModelLogic
public class B : IB<A> { }
// Model Interface
public interface IA { }
// ModelLogic Interface
public interface IB<T> where T : IA { }
Run Code Online (Sandbox Code Playgroud)
我尝试使用以下代码创建一个新实例:
IB<IA> foo = new B();
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
Cannot implicitly convert type 'B' to 'IB<IA>'. An explicit conversion exists (are you missing a cast?)
Run Code Online (Sandbox Code Playgroud)
有人可以解释为什么这是不可能的?
我目前正在尝试使用Java接口和泛型为概念模型实现API.模型(Transmodel V5.0)被详细描述为实体关系模型,但它没有指定使用的一些基本类型.例如,没有定义各种实体的标识符类型或用于在序列中建立排序的类型.
由于我希望尽可能保持API的通用性,因此我开始使用泛型来配置这些细节.我不想对类型做任何假设,包括不假设任何事情是一致的.每个实体可以具有不同的标识符类型,每个序列可以具有用于排序目的的不同类型.
我面临的问题是,一旦一个实体引用另一个实体,复杂性就会快速增长 - 我不仅需要为其标识符传递类型,还需要为配置引用实体所需的所有内容.
例如,我有:
/**
* @param <ID> The type for the identifier of this entity.
* @param <ID_JP> The type identifying journey patterns.
* @param <OP_JP> The ordering used for points in journey patterns.
* @param <JP> The type of journey pattern referenced by this entity.
*/
public interface VehicleJourney<
ID,
ID_JP, OP_JP extends Comparable<OP_JP>, JP extends JourneyPattern<ID_JP, OP_JP>
> extends IdentifiableObject<ID>
{
JP getJourneyPattern();
}
Run Code Online (Sandbox Code Playgroud)
我仍然可以阅读并理解它,但它变得有点冗长.然后可以在其他实体中引用像VehicleJourney这样的实体,这会使类型参数列表爆炸.这几乎是我能想到的最小的非平凡的例子.
有没有办法创建一个单一的Java实体来建模类型系统的整个配置?我正在考虑将附加所有标识符类型和排序类型的东西,然后可以作为一个传递,将上面的示例转换为如下所示:
public interface VehicleJourney<CONF, JP extends JourneyPattern<CONF>>
extends IdentifiableObject<???> …Run Code Online (Sandbox Code Playgroud) 对于以下代码示例:
public static class Abc<X> { }
public static class Def<Y> { }
public static class Ghi<Z> { }
public void doThis() {
List<?> listOne;
List<Abc<?>> listTwo;
List<Abc<Def<?>>> listThree;
List<Abc<Def<Ghi<?>>>> listFour;
List<Abc<Def<Ghi<String>>>> listFive;
Abc<Def<Ghi<String>>> abcdef;
abcdef = new Abc<Def<Ghi<String>>>();
listOne.add(abcdef); // line 1
listTwo.add(abcdef); // line 2
listThree.add(abcdef); // line 3
listFour.add(abcdef); // line 4
listFive.add(abcdef); // line 5
}
Run Code Online (Sandbox Code Playgroud)
第1,3和4行不编译:
(第1行)
The method add(capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (Abc<Def<Ghi<String>>>)
Run Code Online (Sandbox Code Playgroud)
(第3行)
The …Run Code Online (Sandbox Code Playgroud) 显然,C#和C++一样容易受到'>>'lexer困境的影响.
这个C#代码非常有效,它编译并运行得很好:
var List = new Dummy("List");
var Nullable = new Dummy("Nullable");
var Guid = new Dummy("Guid");
var x = List<Nullable<Guid>> 10;
var y = List<Nullable<Guid>> .Equals(10,20);
Run Code Online (Sandbox Code Playgroud)
您必须为上面的Dummy类重载'<'和'>>'运算符.
但编译器设法猜测在'x'情况下,意思是使用List,Nullable和Guid局部变量.在'y'的情况下,它突然决定将它们视为众所周知的类型的名称.
以下是另一个例子的更详细描述:http: //mihailik.blogspot.co.uk/2012/05/nested-generics-c-can-be-stinky.html
问题是:C#编译器如何将'a <b <c >>'解析为算术表达式或泛型类型/方法?
当然,它不会尝试在程序文本上多次"运行",直到它成功,或者它是否成功?这需要无限前瞻,而且非常复杂.
我在使用泛型时理解多态如何工作时遇到了问题.举个例子,我定义了以下程序:
public interface IMyInterface
{
void MyMethod();
}
public class MyClass : IMyInterface
{
public void MyMethod()
{
}
}
public class MyContainer<T> where T : IMyInterface
{
public IList<T> Contents;
}
Run Code Online (Sandbox Code Playgroud)
我可以这样做,这很好用:
MyContainer<MyClass> container = new MyContainer<MyClass>();
container.Contents.Add(new MyClass());
Run Code Online (Sandbox Code Playgroud)
我有很多实现MyInterface的类.我想编写一个可以接受所有MyContainer对象的方法:
public void CallAllMethodsInContainer(MyContainer<IMyInterface> container)
{
foreach (IMyInterface myClass in container.Contents)
{
myClass.MyMethod();
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我想称之为这种方法.
MyContainer<MyClass> container = new MyContainer<MyClass>();
container.Contents.Add(new MyClass());
this.CallAllMethodsInContainer(container);
Run Code Online (Sandbox Code Playgroud)
那没用.当然,因为MyClass实现了IMyInterface,我应该能够实现它吗?
MyContainer<IMyInterface> newContainer = (MyContainer<IMyInterface>)container;
Run Code Online (Sandbox Code Playgroud)
那也行不通.我绝对可以将一个普通的MyClass转换为IMyInterface:
MyClass newClass = new MyClass();
IMyInterface myInterface = (IMyInterface)newClass;
Run Code Online (Sandbox Code Playgroud)
所以,至少我没有完全误解这一点.我不确定我是如何编写一个接受符合相同接口的类的泛型集合的方法. …