[英]Call a method from Static Class passing Type of Dynamic variable with Generics
[英]Call method or class using generics
我對 generics 的實現方式有疑問,希望您能支持或指導我在我的情況下實現它。
好吧,我正在處理文件或畫廊的播放列表,這將能夠播放各種類型的文件格式(mp3、jpg、mp4、obj 等)然后我想避免為每種方法修改我的代碼負責導入這些類型的文件。 我一直在閱讀有關 generics 的信息,我發現它解決了我的問題,但我不知道如何實現它。
你能幫我解決這個問題嗎? 還是可以做我想做的事情?
就這樣。 非常感謝!
這是我在 Unity 中制作的代碼:
腳本 1:
public class GalleryItem : MonoBehaviour
{ #region 變量
[SerializeField]
private GalleryContextMenu contextMenu;
[Header("Settings")]
[SerializeField]
internal Color normalItemColor = Color.white;
[SerializeField]
internal Color hoveredItemColor = new Color32(225, 225, 255, 255);
[SerializeField]
internal Color selectedItemColor = new Color32(0, 175, 255, 255);
[Serializable]
private struct FiletypeIcon
{
public string extension;
public Sprite icon;
}
[Header("Icons")]
[SerializeField]
private FiletypeIcon[] filetypeIcons;
//Listas
private readonly List<int> selectedFileEntries = new List<int>(4);
private readonly List<FileItem> allItems = new List<FileItem>(16);
private readonly List<WidgetItem> allWidgetItems = new List<WidgetItem>();
private List<GameObject> buttonFileList = new List<GameObject>();
internal List<string> allFiles = new List<string>();
//Indice para cada item
internal int sharedValue;
internal string fullFilePath;
//Cantidad de items
private int items;
[Header("Canvas")]
//Contenedor de items
public RectTransform content;
//Item a instanciar
public GameObject itemPrefab;
//Canvas que contiene la galeria de items
public Canvas canvas;
public RectTransform rectTransform;
#endregion
#region MÉTODOS DE INICIALIZACIÓN
private void Awake()
{
items = 0;
}
private void InitializeDataItem()
{
for (int j = 0; j < filetypeIcons.Length; j++)
{
if (fullFilePath.Contains(filetypeIcons[j].extension))
allItems[items].SetFile(filetypeIcons[j].icon, Path.GetFileNameWithoutExtension(fullFilePath));
}
}
#endregion
#region MÉTODOS PARA ABRIR EL EXPLORADOR DE ARCHIVOS
public void StartFileBrowser()
{
StartCoroutine(ShowLoadingCoroutine());
}
IEnumerator ShowLoadingCoroutine()
{
yield return FileBrowser.WaitForLoadDialog(FileBrowser.PickMode.FilesAndFolders, true, null, null, "Abrir archivos y carpetas", "Cargar");
if (FileBrowser.Success)
{
fullFilePath = FileBrowser.Result[0].ToLowerInvariant();
OnCreateItem("item", itemPrefab, content);
OnCreateWidgetItem("WidgetButton");
}
}
#endregion
#region MÉTODO PARA AGREGAR Y ELEIMINAR ELEMENTOS DE LA GALERÍA
public void DeleteItem()
{
Destroy(buttonFileList[sharedValue]);
Destroy(allItems[sharedValue]);
buttonFileList.RemoveAt(sharedValue);
allItems.RemoveAt(sharedValue);
allWidgetItems.RemoveAt(sharedValue);
allFiles.RemoveAt(sharedValue);
items -= 1;
Refresh();
}
private void Refresh()
{
for (int i = 0; i < buttonFileList.Count; i++)
buttonFileList[i].name = "item_" + i;
for (int i = 0; i < allWidgetItems.Count; i++)
{
allWidgetItems[i].gameObject.name = "WidgetButton" + i;
}
if (buttonFileList.Count == 0)
items = 0;
}
private void OnCreateWidgetItem(string name)
{
WidgetItem widget = GameObject.Find("WidgetButton").GetComponentInChildren<WidgetItem>();
widget.name = name + "_" + (items - 1);
allWidgetItems.Add(widget);
}
private void OnCreateItem(string name, GameObject prefab, Transform parent)
{
FileItem item = (FileItem)Instantiate(prefab.GetComponent<FileItem>(), parent, false);
item.name = name + "_" + items;
buttonFileList.Add(item.gameObject);
allItems.Add(item);
allFiles.Add(fullFilePath);
InitializeDataItem();
items += 1;
}
#endregion
#region MENÚ CONTEXTUAL
internal void OnContextMenuTriggered()
{
Vector2 position;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, Input.mousePosition, canvas.worldCamera, out position);
contextMenu.Show(position, false);
}
#endregion
#region HOVER PARA ELEMENTOS
public void OnItemSelected(FileItem item, bool isDobleClick)
{
if (item == null)
return;
if (!isDobleClick)
{
selectedFileEntries.Clear();
selectedFileEntries.Add(item.Position);
}
for (int i = 0; i < allItems.Count; i++)
{
if (allItems[i].gameObject.activeSelf)
allItems[i].SetSelected(false);
}
item.SetSelected(selectedFileEntries.Contains(item.Position));
}
public void OnSelectedWidgetItem()
{
for (int i = 0; i < allWidgetItems.Count; i++)
{
allWidgetItems[i].isPlaying = false;
allWidgetItems[i].PlayingNull();
}
}
腳本 2:
public class GalleryItem : MonoBehaviour
{ #region 變量
[SerializeField]
private GalleryContextMenu contextMenu;
[Header("Settings")]
[SerializeField]
internal Color normalItemColor = Color.white;
[SerializeField]
internal Color hoveredItemColor = new Color32(225, 225, 255, 255);
[SerializeField]
internal Color selectedItemColor = new Color32(0, 175, 255, 255);
[Serializable]
private struct FiletypeIcon
{
public string extension;
public Sprite icon;
}
[Header("Icons")]
[SerializeField]
private FiletypeIcon[] filetypeIcons;
//Listas
private readonly List<int> selectedFileEntries = new List<int>(4);
private readonly List<FileItem> allItems = new List<FileItem>(16);
private readonly List<WidgetItem> allWidgetItems = new List<WidgetItem>();
private List<GameObject> buttonFileList = new List<GameObject>();
internal List<string> allFiles = new List<string>();
//Indice para cada item
internal int sharedValue;
internal string fullFilePath;
//Cantidad de items
private int items;
[Header("Canvas")]
//Contenedor de items
public RectTransform content;
//Item a instanciar
public GameObject itemPrefab;
//Canvas que contiene la galeria de items
public Canvas canvas;
public RectTransform rectTransform;
#endregion
#region MÉTODOS DE INICIALIZACIÓN
private void Awake()
{
items = 0;
}
private void InitializeDataItem()
{
for (int j = 0; j < filetypeIcons.Length; j++)
{
if (fullFilePath.Contains(filetypeIcons[j].extension))
allItems[items].SetFile(filetypeIcons[j].icon, Path.GetFileNameWithoutExtension(fullFilePath));
}
}
#endregion
#region MÉTODOS PARA ABRIR EL EXPLORADOR DE ARCHIVOS
public void StartFileBrowser()
{
StartCoroutine(ShowLoadingCoroutine());
}
IEnumerator ShowLoadingCoroutine()
{
yield return FileBrowser.WaitForLoadDialog(FileBrowser.PickMode.FilesAndFolders, true, null, null, "Abrir archivos y carpetas", "Cargar");
if (FileBrowser.Success)
{
fullFilePath = FileBrowser.Result[0].ToLowerInvariant();
OnCreateItem("item", itemPrefab, content);
OnCreateWidgetItem("WidgetButton");
}
}
#endregion
#region MÉTODO PARA AGREGAR Y ELEIMINAR ELEMENTOS DE LA GALERÍA
public void DeleteItem()
{
Destroy(buttonFileList[sharedValue]);
Destroy(allItems[sharedValue]);
buttonFileList.RemoveAt(sharedValue);
allItems.RemoveAt(sharedValue);
allWidgetItems.RemoveAt(sharedValue);
allFiles.RemoveAt(sharedValue);
items -= 1;
Refresh();
}
private void Refresh()
{
for (int i = 0; i < buttonFileList.Count; i++)
buttonFileList[i].name = "item_" + i;
for (int i = 0; i < allWidgetItems.Count; i++)
{
allWidgetItems[i].gameObject.name = "WidgetButton" + i;
}
if (buttonFileList.Count == 0)
items = 0;
}
private void OnCreateWidgetItem(string name)
{
WidgetItem widget = GameObject.Find("WidgetButton").GetComponentInChildren<WidgetItem>();
widget.name = name + "_" + (items - 1);
allWidgetItems.Add(widget);
}
private void OnCreateItem(string name, GameObject prefab, Transform parent)
{
FileItem item = (FileItem)Instantiate(prefab.GetComponent<FileItem>(), parent, false);
item.name = name + "_" + items;
buttonFileList.Add(item.gameObject);
allItems.Add(item);
allFiles.Add(fullFilePath);
InitializeDataItem();
items += 1;
}
#endregion
#region MENÚ CONTEXTUAL
internal void OnContextMenuTriggered()
{
Vector2 position;
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, Input.mousePosition, canvas.worldCamera, out position);
contextMenu.Show(position, false);
}
#endregion
#region HOVER PARA ELEMENTOS
public void OnItemSelected(FileItem item, bool isDobleClick)
{
if (item == null)
return;
if (!isDobleClick)
{
selectedFileEntries.Clear();
selectedFileEntries.Add(item.Position);
}
for (int i = 0; i < allItems.Count; i++)
{
if (allItems[i].gameObject.activeSelf)
allItems[i].SetSelected(false);
}
item.SetSelected(selectedFileEntries.Contains(item.Position));
}
public void OnSelectedWidgetItem()
{
for (int i = 0; i < allWidgetItems.Count; i++)
{
allWidgetItems[i].isPlaying = false;
allWidgetItems[i].PlayingNull();
}
}
Generics 在您想要一種對操作進行一些描述並將其應用於一堆不同類型的情況下很有用。 例如,您可能想要制作一個可以容納不同類型對象的容器。
在播放列表的情況下,這並不是您真正在做的事情,因為您正在考慮不同類型的對象列表。 相反,您想要的是提供所需功能的基本類型或接口,如下所示:
interface IPlayable
{
void play();
void stop();
void rewind();
// ...
}
class MP3File : IPlayable
{
public void play() { /* ... */ }
// ...
}
class MP3File : IPlayable
{
public void play() { /* ... */ }
// ...
}
class WAVFile : IPlayable
{
public void play() { /* ... */ }
// ...
}
然后你可以將你的播放列表聲明為
System.Collections.Generic.List<IPlayable> myPlaylist;
並做類似的事情
myPlaylist.add(new MP3File("song.mp3"));
myPlaylist[i].play();
你提到想要加載東西。 為此,您可能想要的是工廠方法,就像這樣
IPlayable makePlayable(string filename)
{
switch(Path.getExtension(filename))
{
case ".mp3" : return new MP3File(filename);
case ".wav" : return new WaveFile(filename);
// ...
default: return null; // or throw, or ...
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.