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