简体   繁体   中英

How to pass list of objects as parameter in function and then use object's attributes C#

So that's my function:

public bool CheckUniqueName<T>(string newName, List<T> list)
    {
        for (int i = 0; i < list.Count(); i++)
        {
            if (list[i].name == newName)
            {
                return false;
            }
        }
        return true;
    }

I have this List of Planets: private List<Planet> planetsList = new List<Planet>();

BUT: I'm gonna use other Lists like public List<Colony> ColonyList = new List<Colony>(); That's why I need List<T>

And class Planet :

class Planet
{
    ...
    public string name { get; }
    ... 
}

And I try this: (some stuff) CheckUniqueName(name, planetsList) in other class

As I get it, List<T> doesn't know about the .name attribute.

I tried to create another List and do something like this:

public bool CheckUniqueName<T>(string newName, List<T> list)
    {
        if (list is List<Planet>)
        {
            var newList = planetsList;
        }
        for (int i = 0; i < list.Count(); i++)
        {
            if (list[i].name == newName)
            {
                return false;
            }
        }
        return true;
    }

It didn't work and same things with creating new List didn't work as well.

You can using generic constraints here:

public bool CheckUniqueName<T>(string newName, IEnumerable<T> items)
    where T : INamed

    => !items.Any(i => (i.Name == newName));

public interface INamed
{
    public Name { get; }
}

public class Planet : INamed
{
    public Name { get; }

    public Plant(string name)
    { 
        Name = name;
    }
}

public class Colony : INamed
{
    public Name { get; }

    public Colony(string name)
    { 
        Name = name;
    }
}

Another way to do this is to pass a delegate which knows how to fetch the name property off any type you pass in:

public bool CheckUniqueName<T>(IEnumerable<T> items, string newName, Func<T, string> nameSelector)
{
    foreach (var item in items)
    {
        string name = nameSelector(item);
        if (name == newName)
        {
            return false;
        }
    }

    return true;
}

Call it like this:

CheckUniqueName(planetsList, "name", planet => planet.name);

Then your name property doesn't have to be called name -- it can be called whatever you want.


I wrote a long version of the CheckUniqueName method for clarity, but you could shorten it using linq:

public bool CheckUniqueName<T>(IEnumerable<T> items, string newName, Func<T, string> nameSelector)
{
    return !items.Any(item => newName == nameSelector(item));
}

However once you go this far, you might as well discard the CheckUniqueName method entirely, and instead just write:

!plantsList.Any(x => x.name == "name");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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