![](/img/trans.png)
[英]C# 3.0 generic type inference - passing a delegate as a function parameter
[英]c# compiler error when passing `this` to a delegate that accepts generic parameter
我想利用以下抽象 class 為統一項目創建事件通道。 我無法理解 generics 如何在 C# 中工作(這種語言對我來說是新的),並且在調用偵聽器時收到關於將this
作為參數傳遞的編譯器錯誤。
namespace EventManagers
{
public abstract class EventSubject<T> : MonoBehaviour
{
public delegate void Listener<T>(T eventSubject);
private readonly
List<Listener<T>> _listeners = new List<Listener<T>>();
public void Attach(Listener<T> listener)
{
_listeners.Add(listener);
}
public void Detach(Listener<T> listener)
{
_listeners.Remove(listener);
}
public void NotifyObservers()
{
foreach (Listener<T> listener in _listeners)
{
listener(this);
}
}
}
}
引用讀取listener(this);
:
error CS1503: Argument 1: cannot convert from 'EventManagers.EventSubject<T>' to 'T'
繼承 class 看起來像:
public class Selection : EventSubject<Selection> {
private GameObject selected;
private static Selection _instance;
public static Selection instance
{
get
{
if (!_instance)
{
_instance = FindObjectOfType(typeof (Selection)) as Selection;
if (!_instance) {
throw new Exception("You need a Selection in the scene");
}
}
return _instance;
}
}
public GameObject GetSelection() {
return selected;
}
public void setSelection(GameObject selected) {
this.selected = selected;
NotifyObservers();
}
}
我的問題是:
public abstract class EventSubject<T> : MonoBehaviour { ... }
public class Selection : EventSubject<Selection> { ... }
從您的EventSubject
class 的 POV 來看, typeof(T)
可以是任何東西。 它甚至可以是EventSubject<int>
因為您沒有提供任何where
約束。 編譯器無法知道您期望typeof(T) == this.GetType()
。
您正在尋找的模式在 C++ 中被昵稱為 Curiously recurring template pattern 。 在 C# 中,等效的通用約束是;
public abstract class EventSubject<T> : MonoBehaviour
where T : EventSubject<T>
{
...
public void NotifyObservers()
{
foreach (Listener listener in _listeners)
{
listener((T)this);
}
}
}
public class Selection : EventSubject<Selection> { ... }
這接近您想要的,因為它至少將T
限制為擴展EventSubject<>
的類。 但是編譯器仍然無法證明typeof(T) == this.GetType()
,因此您需要顯式轉換。
此約束還允許class Broken: EventSubject<Selection>
,並且沒有任何 C# 語言功能可以阻止它。 如果開發人員違反了您的typeof(T) == this.GetType()
規則,您可以做的最好的事情就是運行時異常。
Selection
實例,您傳遞this
是一個Listener<Selection>
實例。對於可能正在觀看的其他人,我能夠取得工作成果。 我的 EventSubject class 現在顯示如下:
public abstract class EventSubject<TEventSubject> : MonoBehaviour
{
public delegate void Listener(TEventSubject eventSubject);
private readonly
List<Listener> _listeners = new List<Listener>();
public void Attach(Listener listener)
{
_listeners.Add(listener);
}
public void Detach(Listener listener)
{
_listeners.Remove(listener);
}
public void NotifyObservers(TEventSubject eventSubject)
{
foreach (Listener listener in _listeners)
{
listener(eventSubject);
}
}
}
我的Selection
class 現在看起來像這樣:
public class Selection : EventSubject<Selection> {
private GameObject selected;
private static Selection _instance;
public static Selection instance
{
get
{
if (!_instance)
{
_instance = FindObjectOfType(typeof (Selection)) as Selection;
if (!_instance) {
throw new Exception("You need a Selection in the scene");
}
}
return _instance;
}
}
public GameObject GetSelection() {
return selected;
}
public void setSelection(GameObject selected) {
this.selected = selected;
NotifyObservers(this);
}
}
老實說,我從來沒有解決編譯器為什么不喜歡listener(this)
的謎題,但能夠通過將其作為NotifyObservers
的參數來解決這個問題。 我很想聽聽人們會改變的優化或其他事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.