简体   繁体   English

如何对具有相同类型和名称的变量的不同结构使用通用类型参数?

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

I have a method, ListToString , that takes a list and outputs the name element of all structs in the list. 我有一个方法ListToString ,它接受一个列表并输出列表中所有结构的name元素。 Each struct that I use ListToString for has a name element, but because I can't apply name to a generic type, I need to create an overload of ListToString for each struct. 我使用ListToString每个结构都有一个name元素,但是由于无法将name应用于通用类型,因此需要为每个结构创建ListToString的重载。 This has cost me about a hundred lines. 这花了我大约一百行。

Example of what I want to happen: 我想发生的事的例子:

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;
        }
    }

What happens instead: 相反会发生什么:

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);
}

Each struct has a similar name element, so how can I incorporate a generic parameter to this? 每个结构都有一个相似的name元素,那么如何将通用参数并入呢?

Seems like you're coming form a language which uses duck typing , ie if an object has a property called name , then any code knowing this fact can access this property without knowing the concrete type of the class. 好像您正在使用一种使用鸭子类型的语言,即,如果对象具有名为name的属性,则任何知道此事实的代码都可以访问此属性而无需知道类的具体类型。

Things don't quite work the same way in c# ( dynamic aside). 在c#中,事情并非完全一样( dynamic除外)。 The idiomatic ways of implementing this pattern are either to derive all the relevant structs from a similar base type, or probably more suitable for your case, to have all structs implement an interface, eg IName , which has a property Name , and then add a generic constraint to your method, such as: 实现此模式的惯用方式是从相似的基本类型中派生所有相关的结构,或者可能更适合您的情况,以使所有结构实现一个接口,例如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.
}

You can add a generic constraint: 您可以添加通用约束:

public interface IThingWithAName
{
  string name { get;}
}

Make sure your classes implement IThingWithAName and 确保您的类实现了IThingWithAName和

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

also since you're not modifying the list, you can use: 另外,由于您没有修改列表,因此可以使用:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在编译时获取通用参数类型名称? - How can I get a generic parameter type name at compile time? 我可以在泛型类型 class 中有不同的泛型类型方法吗 - Can I have a different generic type Method in a generic type class 如何将变量用作泛型方法的类型参数 - How to use a variable for the type parameter of a generic method 如何使用泛型类型的类型参数作为方法参数的类型? - How can I use a generic type's type argument as the type of a method parameter? 如何对具有相同成员的不同类型参数使用相同的函数? - How can I use the same function for different type parameters which have the same member? 如何命名相同的变量,但名称不同 - How do I name the same variable but of different type 如何将“Type”类型的变量传递给泛型参数 - How to pass variable of type “Type” to generic parameter 如何在扩展方法中获取&#39;this&#39;参数的泛型类型参数? - How can I get the generic type parameter of the 'this' parameter in an extension method? 我们可以使用返回类型与输入参数类型相同的泛型函数吗? - Can we have a generic function with return type same as input parameter type? 为什么我不能将&#39;as&#39;用于限制为接口的泛型类型参数? - Why can't I use 'as' with generic type parameter that is constrained to be an interface?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM