我可以制作一个通用的可选项,默认为某个类吗?
我的问题与C#generics中“默认”类型参数的合理方法有关吗? ,但使用内部generics类,该方法不起作用。
给出这样的代码:
using System; public class FooEventArgs : EventArgs { // ... T properties and a constructor } public class Foo { public delegate void EventHandler(object sender, FooEventArgs e); public event EventHandler<FooEventArgs> Changed }
并使用它像这样:
public class User { public Foo foo1; public Foo foo2; public User() { foo1 = new Foo(); foo2 = new Foo(); foo1.Changed += foo1_Changed; foo2.Changed += foo2_Changed; } protected void foo1_Changed(object sender, FooEventArgs e) { ... } protected void foo2_Changed(object sender, FooEventArgs e) { ... } }
好吧,如果我可以使用通用可选项,我宁愿喜欢它,因为在很多情况下我不知道会出现什么类型的东西。(数据来自外部系统,它有自己的变量类型,然后转换为.NET类型,但我遇到的情况,例如,一个远程数据类型可能变成几种.NET类型之一,或者它是“任何”类型 – 因此object
将是这个案子唯一真正的答案。)
我立即想到的解决方案是子类化(这也是与之前相关的问题中的主要建议):
public class Foo : Foo { public Foo(...) : base(...) { } } public class FooEventArgs : FooEventArgs { public Foo(...) : base(...) { } }
然后我想像这样使用它:
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
)。
Foo.cs(3,1415926): error CS0123: No overload for 'foo3_Changed' matches delegate 'FooLibrary.Foo.EventHandler<FooLibrary.FooEventArgs>'
有什么我可以做的,没有重复大部分课程吗?
我确实尝试了另一件事:从FooEventArgs
转换为FooEventArgs
的隐式运算符。
public static implicit operator FooEventArgs(FooEventArgs e) { return new FooEventArgs(...); }
不幸的是,这似乎不起作用,虽然我不清楚为什么:
EditBuffer.cs(13,37): error CS0553: 'FooLibrary.FooEventArgs.implicit operator FooLibrary.FooEventArgs(FooLibrary.FooEventArgs)': user-defined conversions to or from a base class are not allowed
那么,再一次,我有什么可以做的,或者我认为这是艰难的运气,我只需要满足于使用FooEventArgs
(然后我想我也可以使用Foo
)?
老实说,我认为你无能为力。 你可以让Foo
通用:
public class Foo where TArgs : FooEventArgs { public delegate void EventHandler(object sender, TArgs e); public event EventHandler Changed; }
然后你可以写:
public class Foo : Foo
……但它确实让事情变得非常复杂,而且收效甚微。
我还要说,即使包含类型参数更加冗长,但它确实非常清楚 – 而inheritance可以通过各种方式使水变得混乱。 当你没有真正尝试模拟行为专业化时,我会避开类inheritance。
隐式转换不起作用的原因与generics无关,顺便说一句 – 正如错误消息所述,您无法声明在inheritance层次结构中上下移动的转换(隐式或显式)。 从C#规范第6.4.1节:
C#仅允许声明某些用户定义的转换。 特别是,无法重新定义已存在的隐式或显式转换。
(有关详细信息,请参阅该部分。)
作为旁注,我发现更常见的是使用inheritance而不是generics,通常使用接口:
public interface IFoo { // Members which don't depend on the type parameter } public interface IFoo : IFoo { // Members which all use T }
这样代码只能接收一个IFoo
而不必担心如果他们不需要知道T
的generics方面。
不幸的是,在您的具体情况下,这对您没有帮助。
我刚发现的另一个有趣的事情是你可以创建具有相同名称但签名不同的generics类。
class Foo { } class Foo { }
然后你可以调用其中一个,如下所示:
new Foo(); new Foo(); new Foo();
我只是觉得有趣的是,尽管两个类具有相同的名称,但它们可以共存,因为它们具有不同的签名。
我猜这就是Tuple类的工作原理