繁体   English   中英

使用 generics 调用方法或 class

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM