How can I make this StringToCollections method more generic? I am new to C# and I have big functions that receives the following arguments:

(Package inPackage, string materialIDs, string functionIDs, string companyIDs)


Asides from the first argument, which is an object of type Package, all the other arguments are strings of IDs. 

So, for example, a valid input for this function would be: myPackage, "1,2,3", ",2,3,4", ",45,2".

A package is an object that contains a list of materials, a list of functions and a list of companies.

The objective of this function, is to look up in the DB all the objects that contain those IDs, and add them to myPackage.

To achieve this objective, this is what I have created:

private Package StringToCollections(Package inPackage, string materialIDs, string functionIDs, string companyIDs)
        {
            //Check Materials Data - Case WITHOUT FORMAT PROTECTION
            var materialList = new List&lt;Material&gt;();
            var materialStringArray = materialIDs.Split(',');
            var materialIdsArray = materialStringArray.Where(x =&gt; x != "").Select(int.Parse);
            materialList.AddRange(DB.Materials.Where(x =&gt; materialIdsArray.Contains(x.MaterialId)));
            inPackage.GATE_Material = materialList;

            //Check Employee_Functions Data - HAS FORMAT PROTECTION ... KINDOFF?
            List&lt;Function&gt; functionsList = new List&lt;Function&gt;();
            string[] functionStringArray = functionIDs.Split(',');
            List&lt;int&gt; functionIdsArray = new List&lt;int&gt;();
            for (int i = 0; i &lt; functionStringArray.Length; i++)
            {
                try
                {
                    functionIdsArray.Add(int.Parse(functionStringArray[i]));
                }
                catch (FormatException)
                {
                    //not a number, ignore - IS THIS A GOOD IDEA!?
                }
            }
            functionsList.AddRange(DB.Function.Where(x =&gt; functionIdsArray.Contains(x.FunctionId)));
            inPackage.Function = functionsList;

            //Check Company Data - ANOTHER WAY OF FORMAT PROTECTION ... KINDOFF?
            if (!companyIDs.IsNullOrWhiteSpace())
            {
                var companiesList = new List&lt;Company&gt;();
                var companyStringArray = companyIDs.Split(',');
                var companyIdsArray = companyStringArray.Where(x =&gt; x != "").Select(int.Parse);
                try
                {
                    companiesList.AddRange(DB.Companies.Where(x =&gt; companyIdsArray.Contains(x.ID)));
                    inPackage.Companies = companiesList;
                }
                catch (FormatException)
                {
                    //do nothing. If the string has an incorrect format, we add nothing and continue.
                }
            }

            return inPackage;
        }


I honestly believe this code is a mess and was hoping that it could be fixed by using C# generics like &lt;T&gt;, but I am not sure if this is possible due to the differences in getting each fields ID and Name.

Is it possible to optimize this function and make it more generic with protection from format exception? if so, how?
Consistency:

Don't mixup using var and declaring your variables explicitly. Choose one of the two, preferably var.

Combining methods:

Use method chaining to shorten your code. There's no need to create a variable for every step your code does. This:

var materialStringArray = materialIDs.Split(',');
var materialIdsArray = materialStringArray.Where(x =&gt; x != "").Select(int.Parse);


can be changed to:

var materialIdsArray = materialIDs.Split(',').Where(x =&gt; x != "").Select(int.Parse);


Generics:

You cannot make one magic generic method to do this. Why? Simply because you do not know the type ahead of time. What you can do however is to create separate method for getting the valid ids from the string:

public IEnumerable&lt;int&gt; GetValidIDs(string ids)
{
    foreach (var id in ids.Split(','))
    {
        int x;
        if (Int32.TryParse(id, out x))
        {
            yield return x;
        }
    }
}

private Package StringToCollections(Package inPackage, string materialIDs, string functionIDs, string companyIDs)
{
    var validMaterialIDs = GetValidIDs(materialIDs);
    var materials = DB.Materials.Where(x =&gt; validMaterialIDs.Contains(x.MaterialId));

    var validFunctionIDs = GetValidIDs(functionIDs);
    var functions = DB.Function.Where(x =&gt; validFunctionIDs.Contains(x.FunctionId)));

    var validCompanyIDs = GetValidIDs(functionIDs);
    var companies = DB.Companies.Where(x =&gt; validCompanyIDs.Contains(x.FunctionId)));

    inPackage.GATE_material = materials;
    inPackage.Function = functions;
    inPackage.Companies = companies;

    return inPackage;
}


Now your code looks much cleaner and is easier to read and maintain, not only by you but also other people.

You can also assign the database call directly to the according property of inPackage, for example:

var validMaterialIDs = GetValidIDs(materialIDs);
inPackage.GATE_material = DB.Materials.Where(x =&gt; validMaterialIDs.Contains(x.MaterialId));