簡體   English   中英

如何對具有相同類型和名稱的變量的不同結構使用通用類型參數?

[英]How can I use a generic type parameter for different structs that have a variable with the same type and name?

我有一個方法ListToString ,它接受一個列表並輸出列表中所有結構的name元素。 我使用ListToString每個結構都有一個name元素,但是由於無法將name應用於通用類型,因此需要為每個結構創建ListToString的重載。 這花了我大約一百行。

我想發生的事的例子:

public static string ListToString<T>(List<T> list, bool formatted)
{
    //Throws many errors because 'T' does not have a 'name' element
    string returnString = "";
    if (formatted)
    {
        if(list.Count == 1)
        {
            returnString += list[0].name;
        }
        else if(list.Count == 2)
        {
            returnString = list[0].name + " and a " + list[1].name;
        }
        else
        {
            for(int i = 0; i < list.Count - 2; i++)
            {
                returnString += list[i].name + ", ";
            }
            returnString += "and a " + list[list.Count - 1].name;
        }
    }

相反會發生什么:

public static string ListToString(List<World.Entities.Resource> list, bool formatted)
{
    string returnString = "";
    if (formatted)
    {
        if(list.Count == 1)
        {
            returnString += list[0].name;
        }
        else if(list.Count == 2)
        {
            returnString = list[0].name + " and a " + list[1].name;
        }
        else
        {
            for(int i = 0; i < list.Count - 2; i++)
            {
                returnString += list[i].name + ", ";
            }
            returnString += "and a " + list[list.Count - 1].name;
        }
    }
    else
    {
        foreach (World.Entities.Resource resource in list)
        {
            returnString += resource.name + ", ";
        }
    }
    return CapitalizeString(returnString);
}
public static string ListToString(List<World.Entities.Creature> list, bool formatted)
{
    string returnString = "";
    if (formatted)
    {
        if (list.Count == 1)
        {
            returnString += list[0].name;
        }
        else if (list.Count == 2)
        {
            returnString = list[0].name + " and a " + list[1].name;
        }
        else
        {
            for (int i = 0; i < list.Count - 2; i++)
            {
                returnString += list[i].name + ", ";
            }
            returnString += "and a " + list[list.Count - 1].name;
        }
    }
    else
    {
        foreach (World.Entities.Creature creature in list)
        {
            returnString += creature.name + ", ";
        }
    }
    return CapitalizeString(returnString);
}
public static string ListToString(List<World.Entities.Structure> list, bool formatted)
{
    string returnString = "";
    if (formatted)
    {
        if (list.Count == 1)
        {
            returnString += list[0].name;
        }
        else if (list.Count == 2)
        {
            returnString = list[0].name + " and a " + list[1].name;
        }
        else
        {
            for (int i = 0; i < list.Count - 2; i++)
            {
                returnString += list[i].name + ", ";
            }
            returnString += "and a " + list[list.Count - 1].name;
        }
    }
    else
    {
        foreach (World.Entities.Structure structure in list)
        {
            returnString += structure.name + ", ";
        }
    }
    return CapitalizeString(returnString);
}
public static string ListToString(List<World.Tools.Tool> list, bool formatted)
{
    string returnString = "";
    if (formatted)
    {
        if (list.Count == 1)
        {
            returnString += list[0].name;
        }
        else if (list.Count == 2)
        {
            returnString = list[0].name + " and a " + list[1].name;
        }
        else
        {
            for (int i = 0; i < list.Count - 2; i++)
            {
                returnString += list[i].name + ", ";
            }
            returnString += "and a " + list[list.Count - 1].name;
        }
    }
    else
    {
        foreach (World.Tools.Tool tool in list)
        {
            returnString += tool.name + ", ";
        }
    }
    return CapitalizeString(returnString);
}

每個結構都有一個相似的name元素,那么如何將通用參數並入呢?

好像您正在使用一種使用鴨子類型的語言,即,如果對象具有名為name的屬性,則任何知道此事實的代碼都可以訪問此屬性而無需知道類的具體類型。

在c#中,事情並非完全一樣( dynamic除外)。 實現此模式的慣用方式是從相似的基本類型中派生所有相關的結構,或者可能更適合您的情況,以使所有結構實現一個接口,例如IName ,該接口具有一個Name屬性,然后添加一個方法的一般約束 ,例如:

public interface IName
{
    string Name { get; }
}

public struct Creature : IName
{
    ...
}

public static string ListToString<T>(List<T> list, bool formatted) where T : IName
{
    ... //The compiler now knows that T is guaranteed to implement IName.
}

您可以添加通用約束:

public interface IThingWithAName
{
  string name { get;}
}

確保您的類實現了IThingWithAName和

public static string ListToString<T>(List<T> list, bool formatted)
  where T : IThingWithAName
{
  // Now you can use list[0].name
}

另外,由於您沒有修改列表,因此可以使用:

public static string ListToString<T>(IReadOnlyList<T> list, bool formatted)
  where T : IThingWithAName

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM