[英]Understanding generics and Func arguments
如果在某個地方回答了這個問題,我不會感到驚訝,問題是我不確定如何用短語表達搜索以找到所需的內容。 我已經發現的東西要么過於簡單以至於無法使用,要么解釋不清,以致於我無法將其轉化為自己的項目。 我沒有事件處理程序,委托等類似的正式指導(哎呀,直到我大學畢業並被聘為程序員之前,我什至沒有了解實體組件系統或其他設計模式),即便如此,這也不是我在工作中或為工作而學到的東西。
基本上我想知道的是,是什么的Array.Sort的定義<T>(T []數組,比較<T>比較) 看起來像什么?
顯然,正在進行某種概括,因為myCompareDelegate(...)接受兩個任意類型的參數。 在我發現的與Func參數有關的幾乎所有內容中,Func <>參數都需要顯式聲明的類型,但某些示例代碼使用的是我不熟悉的運算符:
SomeUtility(arg => new MyType());
public void SomeUtility<T>(Func<object, T> converter) {
var myType = converter("foo");
}
它可以編譯,但是我不知道它是做什么的,因此,我不知道如何利用它來創建將運行或執行我想做的代碼。
我在這里的目標是能夠創建一個事件系統(是的,我知道C#內置了一個事件系統,但是同樣,我所看到的所有示例代碼都被簡化到無用的地步-偵聽器與調度程序包含在同一類中-或復雜且無法解釋)。 我希望以下內容是正確的:
我有一個目前可以正常工作的系統,但是它要求我的所有處理程序都通過一個“ onEvent”函數,該函數接受一個基本事件對象並弄清楚它的實際類型,然后將其傳遞給真正的處理程序。
例如:
//Entity implements IEventDispatcher
public SomeConstructor(Entity ent) {
//public delegate void EventListener(EventBase eventData); is declared
//in the IEventDispatcher interface.
ent.attachEvent(typeof(EntityEventPreRender), new EventListener(onEvent));
ent.attachEvent(typeof(EntityEventPostRender), new EventListener(onEvent));
}
//EntityEventPreRender extends EntityEventRender extends EntityEvent extends EventBase
//EntityEventPostRender extends EntityEventRender extends EntityEvent extends EventBase
public void onEvent(EventBase data) {
if(data is EntityEventPreRender)
onPre((EntityEventPreRender)data);
if(data is EntityEventPostRender)
onPost((EntityEventPostRender)data);
}
public void onPre(EntityEventPreRender evt) {}
public void onPost(EntityEventPostRender evt) {}
這里的attachEvent()是一個接受Type(用作HashMap鍵)和Delegate並將其存儲在列表中(HashMap值)的函數。 調度事件只需要傳遞EventData對象,就可以通過事件數據對象的類型(通過evt.GetType())查詢該對象以檢索偵聽器列表,然后調用它們:listItem(evt)
但是我寧願能夠做到這一點:
public SomeConstructor(Entity ent) {
ent.attachEvent(onPre);
ent.attachEvent(onPost);
}
public void onPre(EntityEventPreRender evt) {}
public void onPost(EntityEventPostRender evt) {}
但是我無法終生解決該問題,因為我不知道如何以Array.Sort <T>(T [] array,Compare的方式聲明attachEvent()函數以采用通用函數參數<T>比較)。 我得到錯誤:
“無法從用法中推斷方法doSomething <T>(SomeClass.Thing <T>)'的類型參數。嘗試顯式指定類型參數。”
我認為您可能正在尋找以下內容:
public static class PubSub<TMessage>
{
private static List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public static void Listen(Action<TMessage> listener)
{
if (listener != null) listeners.Add(listener);
}
public static void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) listeners.Remove(listener);
}
public static void Broadcast(TMessage message)
{
foreach(var listener in listeners) listener(message);
}
}
在上面的代碼中,使用PubSub並為TMessage指定類型將在內存中創建一個新的靜態類,並為其分配自己的存儲空間以存儲單獨的偵聽器列表。 編譯器將確保在該列表中僅允許使用TMessage及其子類的替代類型,前提是您始終使用基本類型作為TMessage類型參數的類型參數。
然后,您將像這樣使用它:
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomePublisher
{
public void DoSomethingCool(string description)
{
var randomizer = new Random();
...
PubSub<SomeMessageType>.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeListener
{
static SomeListener()
{
PubSub<SomeMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeMessageType message)
{
// do something with the message
}
}
如果您隨后創建另一個類SomeOtherMessageType,該類不繼承自SomeMessageType並對其進行類似調用,則它將僅廣播給該特定類型的偵聽器。
編輯:
這是一個完整的概念證明,可以編譯為可以在控制台應用程序中運行,以消除您對該技術功效可能存在的任何其他擔憂。
using System;
using System.Collections.Generic;
namespace TestPubSub
{
public class Program
{
public static void Main(string[] args)
{
Program.startListeners();
Program.sendTestMessages();
Program.stopConsoleFromExitingImmediately();
}
private static void startListeners()
{
SomeListener.Listen();
SomeOtherListener1.Listen();
SomeOtherListener2.Listen();
}
private static void sendTestMessages()
{
var publisher1 = new SomePublisher();
var publisher2 = new SomeOtherPublisher();
publisher1.DoSomethingCool("Hello world");
publisher2.DoSomethingElse(DateTime.Now);
}
private static void stopConsoleFromExitingImmediately()
{
Console.ReadKey();
}
}
public static class PubSub<TMessage>
{
private static List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public static void Listen(Action<TMessage> listener)
{
if (listener != null) listeners.Add(listener);
}
public static void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) listeners.Remove(listener);
}
public static void Broadcast(TMessage message)
{
foreach(var listener in listeners) listener(message);
}
}
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomeOtherMessageType
{
public DateTime SomeDate;
public Double SomeAmount;
}
public class SomePublisher
{
public void DoSomethingCool(string description)
{
var randomizer = new Random();
PubSub<SomeMessageType>.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeOtherPublisher
{
public void DoSomethingElse(DateTime when)
{
var randomizer = new Random();
PubSub<SomeOtherMessageType>.Broadcast(new SomeOtherMessageType(){SomeAmount = randomizer.NextDouble(), SomeDate = when});
}
}
public class SomeListener
{
public static void Listen()
{
PubSub<SomeMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeMessageType message)
{
Console.WriteLine("Attention! SomeMessageType receieved by SomeListener with\r\nid: {0}\r\ndescription: {1}\r\n", message.SomeId, message.SomeDescription);
}
}
public class SomeOtherListener1
{
public static void Listen()
{
PubSub<SomeOtherMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Heads up! SomeOtherMessageType receieved by SomeOtherListener1 with\r\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
public class SomeOtherListener2
{
public static void Listen()
{
PubSub<SomeOtherMessageType>.Listen(SomeMessageEvent);
}
private static void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Yo! SomeOtherMessageType receieved by SomeOtherListener2 withr\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
}
再次編輯(使用基於實例的pubs的概念替代證明):
這是使用基於實例的PubSub的概念證明。
using System;
using System.Collections.Generic;
namespace TestPubSub
{
public class Program
{
private static PubSub<SomeMessageType> pubSub1 = new PubSub<SomeMessageType>();
private static PubSub<SomeOtherMessageType> pubSub2 = new PubSub<SomeOtherMessageType>();
private static SomeListener listener1 = new SomeListener();
private static SomeOtherListener1 listener2 = new SomeOtherListener1();
private static SomeOtherListener2 listener3 = new SomeOtherListener2();
public static void Main(string[] args)
{
Program.startListeners();
Program.sendTestMessages();
Program.stopConsoleFromExitingImmediately();
}
private static void startListeners()
{
Program.listener1.Listen(Program.pubSub1);
Program.listener2.Listen(Program.pubSub2);
Program.listener3.Listen(Program.pubSub2);
}
private static void sendTestMessages()
{
var publisher1 = new SomePublisher(Program.pubSub1);
var publisher2 = new SomeOtherPublisher(Program.pubSub2);
publisher1.DoSomethingCool("Hello world");
publisher2.DoSomethingElse(DateTime.Now);
}
private static void stopConsoleFromExitingImmediately()
{
Console.ReadKey();
}
}
public class PubSub<TMessage>
{
private List
<
Action
<
TMessage
>
> listeners = new List<Action<TMessage>>();
public void Listen(Action<TMessage> listener)
{
if (listener != null) this.listeners.Add(listener);
}
public void Unlisten(Action<TMessage> listener)
{
if (listeners.Contains(listener)) this.listeners.Remove(listener);
}
public void Broadcast(TMessage message)
{
foreach(var listener in this.listeners) listener(message);
}
}
public class SomeMessageType
{
public int SomeId;
public string SomeDescription;
}
public class SomeOtherMessageType
{
public DateTime SomeDate;
public Double SomeAmount;
}
public class SomePublisher
{
private PubSub<SomeMessageType> pubSub;
public SomePublisher(PubSub<SomeMessageType> pubSub) { this.pubSub = pubSub; }
public void DoSomethingCool(string description)
{
var randomizer = new Random();
this.pubSub.Broadcast(new SomeMessageType(){SomeId = randomizer.Next(), SomeDescription = description});
}
}
public class SomeOtherPublisher
{
private PubSub<SomeOtherMessageType> pubSub;
public SomeOtherPublisher(PubSub<SomeOtherMessageType> pubSub) { this.pubSub = pubSub; }
public void DoSomethingElse(DateTime when)
{
var randomizer = new Random();
this.pubSub.Broadcast(new SomeOtherMessageType(){SomeAmount = randomizer.NextDouble(), SomeDate = when});
}
}
public class SomeListener
{
public void Listen(PubSub<SomeMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeMessageType message)
{
Console.WriteLine("Attention! SomeMessageType receieved by SomeListener with\r\nid: {0}\r\ndescription: {1}\r\n", message.SomeId, message.SomeDescription);
}
}
public class SomeOtherListener1
{
public void Listen(PubSub<SomeOtherMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Heads up! SomeOtherMessageType receieved by SomeOtherListener1 with\r\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
public class SomeOtherListener2
{
public void Listen(PubSub<SomeOtherMessageType> pubSub)
{
pubSub.Listen(this.SomeMessageEvent);
}
private void SomeMessageEvent(SomeOtherMessageType message)
{
Console.WriteLine("Yo! SomeOtherMessageType receieved by SomeOtherListener2 withr\namount: {0}\r\ndate: {1}\r\n", message.SomeAmount, message.SomeDate);
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.