Когда я имею к методам записи, которые возвращают два значения, я обычно иду об этом как в следующем коде, который возвращает a List<string>
. Или если я должен возвратиться, например, идентификатор и строка, затем я возвращаю a List<object>
и затем выберите их с индексом и переделайте значения.
Эта переделка и ссылка индексом кажутся неэлегантными, таким образом, я хочу разработать новую привычку для методов, которые возвращают два значения. Каков лучший шаблон для этого?
using System;
using System.Collections.Generic;
using System.Linq;
namespace MultipleReturns
{
class Program
{
static void Main(string[] args)
{
string extension = "txt";
{
List<string> entries = GetIdCodeAndFileName("first.txt", extension);
Console.WriteLine("{0}, {1}", entries[0], entries[1]);
}
{
List<string> entries = GetIdCodeAndFileName("first", extension);
Console.WriteLine("{0}, {1}", entries[0], entries[1]);
}
Console.ReadLine();
}
/// <summary>
/// gets "first.txt", "txt" and returns "first", "first.txt"
/// gets "first", "txt" and returns "first", "first.txt"
/// it is assumed that extensions will always match
/// </summary>
/// <param name="line"></param>
public static List<string> GetIdCodeAndFileName(string line, string extension)
{
if (line.Contains("."))
{
List<string> parts = line.BreakIntoParts(".");
List<string> returnItems = new List<string>();
returnItems.Add(parts[0]);
returnItems.Add(line);
return returnItems;
}
else
{
List<string> returnItems = new List<string>();
returnItems.Add(line);
returnItems.Add(line + "." + extension);
return returnItems;
}
}
}
public static class StringHelpers
{
public static List<string> BreakIntoParts(this string line, string separator)
{
if (String.IsNullOrEmpty(line))
return null;
else
{
return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList();
}
}
}
}
Хорошо, спасибо все, мне нравится "возврат, на который пользовательский класс" отвечает лучше всего, никогда действительно думал out
было это легкое читать, кажется, что взлом мне возвращающий первую переменную один путь и второе другой, вот является моим рефакторингом, возвращая пользовательский класс:
using System;
using System.Collections.Generic;
using System.Linq;
namespace MultipleReturns
{
class Program
{
static void Main(string[] args)
{
string extension = "txt";
{
IdCodeFileNamePair pair = GetIdCodeAndFileName("first.txt", extension);
Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName);
}
{
IdCodeFileNamePair pair = GetIdCodeAndFileName("first", extension);
Console.WriteLine("{0}, {1}", pair.IdCode, pair.FileName);
}
Console.ReadLine();
}
/// <summary>
/// gets "first.txt", "txt" and returns "first", "first.txt"
/// gets "first", "txt" and returns "first", "first.txt"
/// it is assumed that extensions will always match
/// </summary>
/// <param name="line"></param>
public static IdCodeFileNamePair GetIdCodeAndFileName(string line, string extension)
{
if (line.Contains("."))
{
List<string> parts = line.BreakIntoParts(".");
List<string> returnItems = new List<string>();
return new IdCodeFileNamePair { IdCode = parts[0], FileName = line };
}
else
{
List<string> returnItems = new List<string>();
return new IdCodeFileNamePair { IdCode = line, FileName = line + "." + extension };
}
}
}
public static class StringHelpers
{
public static List<string> BreakIntoParts(this string line, string separator)
{
if (String.IsNullOrEmpty(line))
return null;
else
{
return line.Split(new string[] { separator }, StringSplitOptions.None).Select(p => p.Trim()).ToList();
}
}
}
public class IdCodeFileNamePair
{
public string IdCode { get; set; }
public string FileName { get; set; }
}
}
Я предпочитаю либо создать облегченный класс с двумя свойствами (см. Ниже), либо использовать кортеж (теперь он встроен в структуру .NET 4 но написать свой собственный несложно)
class MyReturnValue
{
public string Id { get; set; }
public string Name { get; set; }
}
Другой вариант - вернуть KeyValuePair <интервал, строка>
.
Используйте ключевое слово out
http://msdn.microsoft.com/en-us/library/ee332485.aspx
Это способ лучше, чем приведение конкретных элементов списка объектов.
Я либо использую out params, либо создаю struct со свойствами (для синтаксиса инициализатора свойств) и возвращаю его. Создание пользовательской структуры/класса имеет преимущество в том, что именование переменных может соответствовать передаваемым данным. Это делает код более читабельным.
IdAndString GetIDAndString()
{
return new IdAndString()
{
ID = 1,
Str = "123"
};
}
struct IdAndString
{
public int ID { get; set; }
public string Str { get; set; }
}
В C# просто нет элегантного способа вернуть два значения. Хотя я определенно считаю, что использование параметров out
лучше, чем возвращение List
, это не очень удобно для сопровождения и чтения. Разработчики C# ожидают out
, он поддерживается непосредственно языком, и хорошо понятно, что он делает.
Начиная с версии 4.0, вместо него можно использовать Tuple
.
Я бы рекомендовал использовать предмет небольшого веса, как предложил Марк. Но есть и другие шаблоны.
Еще один простой подход - использование свойства call by reference. Например, вызывающая сторона отправляет пустой массив в качестве параметра, который будет заполнен функцией.
Почему бы не public static void GetIdCodeAndFileName(string line, string extension, out string id, out string fileName)
?
Как насчет шаблона Pair
? Конечно, вы можете создать собственные типы данных для этого, если будут передаваться одни и те же данные, но это не так универсально.
(Или, может быть, C# позволяет генерировать классы на лету? update: ok ignore this bit)