Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 我可以将泛型设置为可选,默认设置为某个类吗?_C#_Generics_.net 3.5 - Fatal编程技术网

C# 我可以将泛型设置为可选,默认设置为某个类吗?

C# 我可以将泛型设置为可选,默认设置为某个类吗?,c#,generics,.net-3.5,C#,Generics,.net 3.5,我的问题与有关,但使用内部泛型类,这种方法不起作用 给定如下代码: using System; public class FooEventArgs<T> : EventArgs { // ... T properties and a constructor } public class Foo<T> { public delegate void EventHandler<FooEventArgs>(object sender, FooEve

我的问题与有关,但使用内部泛型类,这种方法不起作用

给定如下代码:

using System;

public class FooEventArgs<T> : EventArgs
{
    // ... T properties and a constructor
}

public class Foo<T>
{
    public delegate void EventHandler<FooEventArgs>(object sender, FooEventArgs<T> e);
    public event EventHandler<FooEventArgs<T>> Changed
}
public class User
{
    public Foo<int> foo1;
    public Foo<object> foo2;

    public User()
    {
        foo1 = new Foo<int>();
        foo2 = new Foo<object>();
        foo1.Changed += foo1_Changed;
        foo2.Changed += foo2_Changed;
    }

    protected void foo1_Changed(object sender, FooEventArgs<int> e) { ... }
    protected void foo2_Changed(object sender, FooEventArgs<object> e) { ... }
}
public class User
{
    public Foo foo3;

    public User()
    {
        foo3 = new Foo();
        foo3.Changed += foo3_Changed;
    }

    protected void foo3_Changed(object sender, FooEventArgs e) { ... }
}
然后我想这样使用它:

using System;

public class FooEventArgs<T> : EventArgs
{
    // ... T properties and a constructor
}

public class Foo<T>
{
    public delegate void EventHandler<FooEventArgs>(object sender, FooEventArgs<T> e);
    public event EventHandler<FooEventArgs<T>> Changed
}
public class User
{
    public Foo<int> foo1;
    public Foo<object> foo2;

    public User()
    {
        foo1 = new Foo<int>();
        foo2 = new Foo<object>();
        foo1.Changed += foo1_Changed;
        foo2.Changed += foo2_Changed;
    }

    protected void foo1_Changed(object sender, FooEventArgs<int> e) { ... }
    protected void foo2_Changed(object sender, FooEventArgs<object> e) { ... }
}
public class User
{
    public Foo foo3;

    public User()
    {
        foo3 = new Foo();
        foo3.Changed += foo3_Changed;
    }

    protected void foo3_Changed(object sender, FooEventArgs e) { ... }
}
问题是,它自然无法与
foo3_Changed
接受
FooEventArgs
;它需要
FooEventArgs
,因为
Foo.Changed
事件将传递给它(因为值将来自
Foo

不幸的是,这似乎不起作用,尽管我不太清楚原因:

EditBuffer.cs(13,37): error CS0553: 'FooLibrary.FooEventArgs.implicit operator FooLibrary.FooEventArgs(FooLibrary.FooEventArgs<object>)': user-defined conversions to or from a base class are not allowed
EditBuffer.cs(13,37):错误CS0553:“愚库.FooEventArgs.implicit运算符愚库.FooEventArgs(愚库.FooEventArgs)”:不允许与基类进行用户定义的转换

那么,再一次,我能做些什么吗?或者我认为这很不幸,我只能满足于使用
FooEventArgs
(然后我想我也可以只使用
Foo
)?

老实说,我认为你对此无能为力。您可以使
Foo
双重通用:

public class Foo<TData, TArgs> where TArgs : FooEventArgs<TData>
{
    public delegate void EventHandler<TArgs>(object sender, TArgs e);
    public event EventHandler<TArgs> Changed;
}
公共类Foo,其中targets:FooEventArgs
{
公共委托void EventHandler(对象发送方,目标);
公共事件事件处理程序已更改;
}
然后你可以写:

public class Foo : Foo<object, FooEventArgs>
公共类Foo:Foo
。。。但这真的让事情变得非常复杂,几乎没有什么好处

我还想说,尽管包含类型参数有点冗长,但它确实非常清楚——而继承可能会以各种方式搅乱局面。当您没有真正尝试建模行为专门化时,我会避开类继承

顺便说一下,隐式转换不起作用的原因与泛型无关——正如错误消息所述,您不能声明继承层次结构上下的转换(隐式或显式)。根据C#规范第6.4.1节:

C#只允许声明某些用户定义的转换。特别是,无法重新定义已存在的隐式或显式转换

(有关详细信息,请参见该部分。)


作为补充说明,我发现对于泛型使用继承的方式更为常见,通常是使用接口:

public interface IFoo
{
    // Members which don't depend on the type parameter
}

public interface IFoo<T> : IFoo
{
    // Members which all use T
}
公共接口IFoo
{
//不依赖于类型参数的成员
}
公共接口IFoo:IFoo
{
//所有使用T的成员
}
这样代码就可以只接收一个
IFoo
,而不必担心泛型方面的问题,如果他们不需要知道
t


不幸的是,这对您的具体情况没有帮助。

我刚刚发现的另一件有趣的事情是,您可以创建具有相同名称但不同签名的泛型类

class Foo<T> { 

}

class Foo<T,T> { 

}
class Foo{
}
类Foo{
}
然后,您可以按如下方式调用其中一个:

new Foo<string>();
new Foo<int,double>();
new Foo<string,int>();
newfoo();
新Foo();
新Foo();
我只是觉得有趣的是,尽管两个类有相同的名称,但它们可以共存,因为它们有不同的签名

我想这就是Tuple类的工作原理

公共类元组
{ 
...

这是一个关于处理接口继承的相反方式的有趣见解。但正如您所观察到的,这在这种情况下是不行的。谢谢。@ChrisMorgan:是的-我只是把它作为一个次要问题提出来。我用另一个想法编辑了答案的开头,但它不是我真正喜欢的。不,我也不喜欢它……那么,明确地说我想是的。乔恩总是回答得很好。回答得很好。这和重载方法很相似work@mojoblanco在班级层面上也是如此。