使用泛型类型参数对类型进行 C# 扩展方法
我正在寻找提高我正在开发的应用程序中某些代码的一致性、简洁性和可读性的方法。起始代码看起来像这样:
context.GetGraphType<Bar>().Subscribe<Fizz>(
(instance, evt) => evt.Execute((Bar)instance.Instance)
);
有许多与上面几乎相同的代码行。我想将其重写为如下所示:
typeof(Bar).SubscribeTo<Fizz>(context);
一方面,这将使我能够利用已经成为非正式约定的形式。另外,我希望它现在会读成“bar 在给定上下文中订阅 fizz 事件”,而不是“上下文获取 bar 类型并订阅 fizz,然后执行一些操作”。我认为流程更好,我询问的同事也同意。
我开始将其作为扩展方法来实现。为了完成上述任务,我想使用事件类型的抽象通用基类,因此 Fizz
将是 Event
。这意味着扩展方法的泛型类型参数必须被限制为调用扩展方法的类型。因此,对于上面的示例,Fizz
必须是 Event
类型。
这可能吗?与此同时,我采用了替代解决方案,但我仍然很好奇它是否可以实现。也欢迎其他建议。
谢谢!
编辑#1:需要明确的是,我意识到我可以使用额外的类型参数,但我正在寻找可能的方法来避免这种情况。
编辑#2: 我想我会对已接受的答案略有不同,因为它与我的场景并不 100% 匹配。最重要的是,可以使用通用静态类代替 Type 的扩展方法来实现我的目标。谢谢dss539!
更新代码(可能有拼写错误,因为我是即时执行此操作):
public class Bar { }
public class Event<TSubscriber>
{
public abstract void Execute(TSubscriber source);
}
public class Fizz : Event<Bar>
{
public override void Execute(Bar bar)
{
// respond to event
}
}
public class Context { }
public static class ForType<TSubscriber>
{
public static void SubscribeTo<TEvent>(Context context)
where TEvent : Event<TSubscriber>
{
context.GetType<TSubscriber>().Subscribe<TEvent>(
(evt, args) => evt.Execute((TSubscriber)args.Source));
}
}
public static void Run()
{
ForType<Bar>.SubscribeTo<Fizz>(context);
}
I’m looking at ways to improve the consistency, brevity, and readability of some code in the application I’m working on. The starting code looked something like this:
context.GetGraphType<Bar>().Subscribe<Fizz>(
(instance, evt) => evt.Execute((Bar)instance.Instance)
);
There are a number of nearly identical lines of code like the above. I wanted to rewrite it to look something like this:
typeof(Bar).SubscribeTo<Fizz>(context);
For one thing, this would allow me to take advantage of formalizing what had already become an informal convention. Also, I hoped that it would now read something like “bar subscribes to the fizz event on the given context”, rather than “the context gets the bar type and subscribes to fizz and then does some stuff.” I think that the flow is better, and the coworker I asked about it agreed.
I started to implement this as an extension method. In order to accomplish the above I wanted to make use of an abstract generic base class for the event type, so Fizz
would be Event<T>
. This would mean that the generic type argument to the extension method would have to be constrained to be of the type that the extension method is called for. So, for the above example, Fizz
would have to be of type Event<Bar>
.
Is this possible? I went with an alternative solution in the mean time, but I am still curious if it can be accomplished. Other suggestions are welcome as well.
Thanks!
Edit #1: Just to be clear, I realize that I could use an additional type parameter, but I'm looking for ways to avoid that if possible.
Edit #2:
I think I'm going to go with a slight variation of the accepted answer, since it doesn't match up 100% with my scenario. The bottom line is that a generic static class can be used instead of an extension method of Type to accomplish my goal. Thanks dss539!
Update code (there may be typos since I'm doing this on the fly):
public class Bar { }
public class Event<TSubscriber>
{
public abstract void Execute(TSubscriber source);
}
public class Fizz : Event<Bar>
{
public override void Execute(Bar bar)
{
// respond to event
}
}
public class Context { }
public static class ForType<TSubscriber>
{
public static void SubscribeTo<TEvent>(Context context)
where TEvent : Event<TSubscriber>
{
context.GetType<TSubscriber>().Subscribe<TEvent>(
(evt, args) => evt.Execute((TSubscriber)args.Source));
}
}
public static void Run()
{
ForType<Bar>.SubscribeTo<Fizz>(context);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这并不完全像你问的那样,但也许就足够了。
This is not exactly like you asked, but maybe it will suffice.
为什么不做一些更自动化的事情,您可以使用通用约束来强制执行规则:
调用看起来像:
约束
where TEvent : Event
确保事件和订阅之间的关系键入您想要的内容。在我的书中,它也比类Type
上的扩展方法更可取 - 因为这往往会使智能感知变得混乱。Type
在许多情况下都会使用,并且在所有Type
实例上的 Intellisense 中出现虚假方法往往会造成混乱。对于图书馆的消费者来说,这是“订阅”的方式也是不明显的 - 除非他们实际上已经看到了它的代码示例。Why not do something a bit more idomatic, where you could use generic constraints to enforce the rules:
The calls would look like:
The constraint
where TEvent : Event<TSub>
ensures the relationship between the event and subscription type that you desire. It's also preferrable in my book to an extension method on the classType
- because that tends to clutter intellisense.Type
is used in many situations, and having spurious methods appear in Intellisense on all instances ofType
tends to be confusing. It's also non-obvious for consumers of library that this is the way to "subscribe" - unless they've actually seen a code example of it.您可能可以接近扩展
System.Type
(以具有typeof(T).
)并向上下文添加一个(扩展)方法,将 .NET 类型转换为您的内部类型类型表示(与 GetGraphType 返回的相同)。...
You can probably get close extending
System.Type
(to havetypeof(T).
) and adding an (extension) method to context that transforms a .NET type to your internal type representation (same as returned byGetGraphType
)....