Tuple을 에서 사용할 수 있는 실용적인 예입니다.넷 4.0?
에 소개된 튜플을 보았습니다.넷 4 하지만 어디에 사용할 수 있는지 상상할 수 없습니다.언제든지 사용자 지정 클래스 또는 구조를 만들 수 있습니다.
그것이 요점입니다. 항상 사용자 지정 클래스나 구조를 만들지 않는 것이 더 편리합니다.그것은 다음과 같은 개선입니다.Action
또는Func
이 유형은 직접 만들 수 있지만 프레임워크에 존재하는 것이 편리합니다.
튜플을 사용하면 2차원 사전을 쉽게 구현할 수 있습니다.예를 들어 다음과 같은 사전을 사용하여 환전 매핑을 구현할 수 있습니다.
var forex = new Dictionary<Tuple<string, string>, decimal>();
forex.Add(Tuple.Create("USD", "EUR"), 0.74850m); // 1 USD = 0.74850 EUR
forex.Add(Tuple.Create("USD", "GBP"), 0.64128m);
forex.Add(Tuple.Create("EUR", "USD"), 1.33635m);
forex.Add(Tuple.Create("EUR", "GBP"), 0.85677m);
forex.Add(Tuple.Create("GBP", "USD"), 1.55938m);
forex.Add(Tuple.Create("GBP", "EUR"), 1.16717m);
forex.Add(Tuple.Create("USD", "USD"), 1.00000m);
forex.Add(Tuple.Create("EUR", "EUR"), 1.00000m);
forex.Add(Tuple.Create("GBP", "GBP"), 1.00000m);
decimal result;
result = 35.0m * forex[Tuple.Create("USD", "EUR")]; // USD 35.00 = EUR 26.20
result = 35.0m * forex[Tuple.Create("EUR", "GBP")]; // EUR 35.00 = GBP 29.99
result = 35.0m * forex[Tuple.Create("GBP", "USD")]; // GBP 35.00 = USD 54.58
MSDN 잡지에 투플을 BCL에 추가하기 위해 들어간 배 아픈 것과 디자인 고려 사항에 대해 이야기하는 훌륭한 기사가 있습니다.값 유형과 참조 유형 중에서 선택하는 것은 특히 흥미롭습니다.
기사에서 분명히 알 수 있듯이, Tuple의 원동력은 Microsoft 내부의 수많은 그룹이 F# 팀을 선두로 사용하고 있기 때문입니다.언급되지는 않았지만, C#(및 VB.NET)의 새로운 "동적" 키워드도 관련이 있다고 생각합니다. 튜플은 동적 언어에서 매우 일반적입니다.
그렇지 않으면 자신만의 포코를 만드는 것보다 특별히 뛰어나지 않습니다. 적어도 구성원에게 더 나은 이름을 지정할 수 있습니다.
업데이트: C# 버전 7의 대규모 개정이 예정되어 있으며, 이제 훨씬 더 많은 구문 사랑을 받고 있습니다.이 블로그 게시물의 예비 공지.
여기에 사용자 ID가 지정된 사용자의 핸들과 전자 메일 주소를 조회해야 하는 방법이 있다고 가정해 보겠습니다.언제든지 해당 데이터를 포함하는 사용자 지정 클래스를 만들거나 해당 데이터에 ref/out 매개 변수를 사용할 수 있으며, 새 POCO를 만들지 않고 Tuple을 반환하고 적절한 메서드 서명을 가질 수 있습니다.
public static void Main(string[] args)
{
int userId = 0;
Tuple<string, string> userData = GetUserData(userId);
}
public static Tuple<string, string> GetUserData(int userId)
{
return new Tuple<string, string>("Hello", "World");
}
오일러 프로젝트의 11번 문제를 풀기 위해 튜플을 사용했습니다.
class Grid
{
public static int[,] Cells = { { 08, 02, 22, // whole grid omitted
public static IEnumerable<Tuple<int, int, int, int>> ToList()
{
// code converts grid to enumeration every possible set of 4 per rules
// code omitted
}
}
이제 다음을 통해 전체 문제를 해결할 수 있습니다.
class Program
{
static void Main(string[] args)
{
int product = Grid.ToList().Max(t => t.Item1 * t.Item2 * t.Item3 * t.Item4);
Console.WriteLine("Maximum product is {0}", product);
}
}
커스텀 타입을 사용할 수도 있었지만, 튜플과 똑같이 생겼을 것입니다.
C#의 튜플 구문은 터무니없이 크기 때문에 튜플을 선언하기가 어렵습니다.그리고 그것은 패턴 매칭이 되지 않기 때문에 사용하기에도 고통스럽습니다.
그러나 때때로 클래스를 만들지 않고 개체를 임시로 그룹화하기만 하면 됩니다.예를 들어, 목록을 집계하려고 했는데 하나 대신 두 개의 값이 필요했다고 가정해 보겠습니다.
// sum and sum of squares at the same time
var x =
Enumerable.Range(1, 100)
.Aggregate((acc, x) => Tuple.Create(acc.Item1 + x, acc.Item2 + x * x));
값 집합을 단일 결과로 결합하는 대신 단일 결과를 값 집합으로 확장합니다.이 함수를 쓰는 가장 쉬운 방법은 다음과 같습니다.
static IEnumerable<T> Unfold<T, State>(State seed, Func<State, Tuple<T, State>> f)
{
Tuple<T, State> res;
while ((res = f(seed)) != null)
{
yield return res.Item1;
seed = res.Item2;
}
}
f
일부 상태를 튜플로 변환합니다.튜플의 첫 번째 값을 반환하고 새 상태를 두 번째 값으로 설정합니다.이를 통해 계산 내내 상태를 유지할 수 있습니다.
다음과 같이 사용합니다.
// return 0, 2, 3, 6, 8
var evens =
Unfold(0, state => state < 10 ? Tuple.Create(state, state + 2) : null)
.ToList();
// returns 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
var fibs =
Unfold(Tuple.Create(0, 1), state => Tuple.Create(state.Item1, Tuple.Create(state.Item2, state.Item1 + state.Item2)))
.Take(10).ToList();
evens
, 꽤간하만지단,만▁is,fibs
조금 더 영리합니다.그것의.state
실제로는 각각 fib(n-2)와 fib(n-1)를 고정하는 튜플입니다.
그들이 악용되는 것을 좋아하지는 않습니다. 그들은 자체를 설명할 수 없는 코드를 생성하기 때문입니다. 하지만 그들은 I StructuralEquatable과 I StructuralComparable을 구현하기 때문에(검색과 주문 목적 모두에 사용하기 위해) 즉석에서 복합 키를 구현하는 것은 훌륭합니다.
또한 모든 항목의 해시 코드를 내부적으로 결합합니다. 예를 들어 Tuple의 GetHashCode(ILSpy에서 가져온)는 다음과 같습니다.
int IStructuralEquatable.GetHashCode(IEqualityComparer comparer)
{
return Tuple.CombineHashCodes(comparer.GetHashCode(this.m_Item1), comparer.GetHashCode(this.m_Item2), comparer.GetHashCode(this.m_Item3));
}
튜플은 한 번에 여러 비동기 IO 작업을 수행하고 모든 값을 함께 반환하는 데 유용합니다.다음은 Tuple을 사용하거나 사용하지 않는 경우의 예입니다.튜플은 실제로 여러분의 코드를 더 명확하게 만들 수 있습니다!
다음을 제외하고(나쁘게 중첩!):
Task.Factory.StartNew(() => data.RetrieveServerNames())
.ContinueWith(antecedent1 =>
{
if (!antecedent1.IsFaulted)
{
ServerNames = KeepExistingFilter(ServerNames, antecedent1.Result);
Task.Factory.StartNew(() => data.RetrieveLogNames())
.ContinueWith(antecedent2 =>
{
if (antecedent2.IsFaulted)
{
LogNames = KeepExistingFilter(LogNames, antecedent2.Result);
Task.Factory.StartNew(() => data.RetrieveEntryTypes())
.ContinueWith(antecedent3 =>
{
if (!antecedent3.IsFaulted)
{
EntryTypes = KeepExistingFilter(EntryTypes, antecedent3.Result);
}
});
}
});
}
});
튜플 포함
Task.Factory.StartNew(() =>
{
List<string> serverNames = data.RetrieveServerNames();
List<string> logNames = data.RetrieveLogNames();
List<string> entryTypes = data.RetrieveEntryTypes();
return Tuple.Create(serverNames, logNames, entryTypes);
}).ContinueWith(antecedent =>
{
if (!antecedent.IsFaulted)
{
ServerNames = KeepExistingFilter(ServerNames, antecedent.Result.Item1);
LogNames = KeepExistingFilter(LogNames, antecedent.Result.Item2);
EntryTypes = KeepExistingFilter(EntryTypes, antecedent.Result.Item3);
}
});
만약 당신이 암시적인 유형의 익명 함수를 사용하고 있었다면, 당신은 튜플을 사용하여 코드를 덜 명확하게 만들지 않았을 것입니다.메서드에서 튜플을 다시 튜닝하시겠습니까?코드 명확성이 중요할 때는 적게 사용하십시오.C#의 기능적 프로그래밍이 저항하기 어렵다는 것을 알지만, 우리는 그 오래된 "객체 지향적인" C# 프로그래머들을 모두 고려해야 합니다.
튜플은 더 많은 일을 할 수 있는 기능적인 언어에서 많이 사용됩니다. 이제 F#은 C#의 '공식' .net 언어입니다. 두 언어로 작성된 코드 간에 이를 전달할 수 있습니다.
나는 피하는 편입니다.Tuple
가독성을 해치기 때문에 대부분의 시나리오에서 사용할 수 있습니다. 하만지,Tuple
관련 없는 데이터를 그룹화해야 하는 경우 유용합니다.
예를 들어, 자동차 목록과 자동차가 구입된 도시가 있다고 가정합니다.
Mercedes, Seattle
Mustang, Denver
Mercedes, Seattle
Porsche, Seattle
Tesla, Seattle
Mercedes, Seattle
도시별로 각 차량의 카운트를 집계하려고 합니다.
Mercedes, Seattle [3]
Mustang, Denver [1]
Porsche, Seattle [1]
Tesla, Seattle [1]
이 작업을 수행하려면 다음을 만듭니다.Dictionary
가 있습니다: " 가 옵 있 다 니 습 이 몇 션 지 다 니 있 ▁you 습 :몇 ▁have
- 성을 합니다.
Dictionary<string, Dictionary<string, int>>
. - 성을 합니다.
Dictionary<CarAndCity, int>
. - 성을 합니다.
Dictionary<Tuple<string, string>, int>
.
첫 번째 옵션에서는 가독성이 손실됩니다.코드를 훨씬 더 많이 작성해야 합니다.
두 번째 옵션은 효과적이고 간결하지만, 자동차와 도시는 실제로 관련이 없으며 아마도 함께 클래스에 속하지 않을 것입니다.
세 번째 방법은 간결하고 깨끗합니다.그것은 유용합니다.Tuple
.
즉석에서 몇 가지 예를 들어보겠습니다.
- X 및 Y 위치(원하는 경우 Z)
- 폭과 높이
- 시간이 지남에 따라 측정된 모든 것
예를 들어 시스템을 포함하지 않을 수 있습니다.포인트/포인트F 및 크기/크기F를 사용하기 위해 웹 응용프로그램에 도면을 작성합니다.
은 당은사용매합니다야주해의우를 사용할 때 매우 조심해야 합니다.Tuple
그리고 아마도 이것을 하기 전에 두 번 생각할 것입니다.을 통해 이의경서저는사것다알는니을았습용하전험에다▁using니▁from알습았▁that▁exper▁out를 사용한다는 것을 알게 되었습니다.Tuple
코드를 읽고 향후 지원하기가 매우 어려워집니다.얼마 전, 저는 튜플이 거의 모든 곳에서 사용되는 코드를 수정해야 했습니다.적절한 객체 모델에 대해 생각하는 대신, 그들은 튜플을 사용했습니다.한 사람을 가끔은 코드를 작성한 사람을 죽이고 싶었죠
사용하지 말아야 한다는 말은 하고 싶지 않습니다.Tuple
는 100% 합니다. 그리고 저는 그고그사것나뭔다는고 100% ▁the▁tasks다%▁and▁are▁percent▁some▁i니▁or그확▁and▁there▁it▁something.Tuple
사용하기에 가장 좋은 후보입니다. 하지만 아마도 다시 생각해보셔야 할 것입니다. 당신은 그것이 정말로 필요한가요?
내가 찾은 튜플의 가장 좋은 용도는 메소드에서 하나 이상의 객체 유형을 반환해야 할 때이며, 어떤 객체 유형과 번호가 될 것인지 알고 있으며 긴 목록이 아닙니다.
다른 간단한 대안으로는 'out' 매개 변수를 사용하는 것이 있습니다.
private string MyMethod(out object)
또는 사전 만들기
Dictionary<objectType1, objectType2>
그러나 Tuple을 사용하면 'out' 개체를 만들거나 기본적으로 사전에서 항목을 검색해야 하는 것을 절약할 수 있습니다.
투플에서 제 문제 중 하나의 해결책을 찾았습니다.메소드의 범위에서 클래스를 선언하지만 필드 이름을 느리게 선언하는 것과 같습니다.단일 인스턴스인 튜플 컬렉션으로 작업한 다음 튜플을 기반으로 필요한 필드 이름을 가진 익명 유형 컬렉션을 만듭니다.이렇게 하면 이 용도로 새 클래스를 만들 수 없습니다.
작업은 추가 클래스 없이 LINQ에서 JSON 응답을 작성하는 것입니다.
//I select some roles from my ORM my with subrequest and save results to Tuple list
var rolesWithUsers = (from role in roles
select new Tuple<string, int, int>(
role.RoleName,
role.RoleId,
usersInRoles.Where(ur => ur.RoleId == role.RoleId).Count()
));
//Then I add some new element required element to this collection
var tempResult = rolesWithUsers.ToList();
tempResult.Add(new Tuple<string, int, int>(
"Empty",
-1,
emptyRoleUsers.Count()
));
//And create a new anonimous class collection, based on my Tuple list
tempResult.Select(item => new
{
GroupName = item.Item1,
GroupId = item.Item2,
Count = item.Item3
});
//And return it in JSON
return new JavaScriptSerializer().Serialize(rolesWithUsers);
물론 우리 그룹에 대한 새로운 클래스를 선언하는 것으로 이것을 할 수 있지만, 새로운 클래스를 선언하지 않고 이러한 익명의 컬렉션을 만드는 아이디어.
저의 경우, 비동기식 방식으로는 매개변수를 사용할 수 없다는 것을 알았을 때 저는 튜플을 사용해야 했습니다.여기에서 그것에 대해 읽어보세요.저는 또한 다른 반품 타입이 필요했습니다.그래서 나는 반품 타입으로 튜플을 대신 사용했고 그 방법을 비동기로 표시했습니다.
아래의 샘플 코드.
...
...
// calling code.
var userDetails = await GetUserDetails(userId);
Console.WriteLine("Username : {0}", userDetails.Item1);
Console.WriteLine("User Region Id : {0}", userDetails.Item2);
...
...
private async Tuple<string,int> GetUserDetails(int userId)
{
return new Tuple<string,int>("Amogh",105);
// Note that I can also use the existing helper method (Tuple.Create).
}
Tuple에 대한 자세한 내용은 여기를 참조하십시오.이게 도움이 되길 바랍니다.
와이어를 통해 개체를 전송하거나 다른 애플리케이션 계층 및 여러 개체로 전달해야 할 때 개체 모양을 변경하면 다음과 같이 하나로 병합됩니다.
예:
var customerDetails = new Tuple<Customer, List<Address>>(mainCustomer, new List<Address> {mainCustomerAddress}).ToCustomerDetails();
확장 방법:
public static CustomerDetails ToCustomerDetails(this Tuple<Website.Customer, List<Website.Address>> customerAndAddress)
{
var mainAddress = customerAndAddress.Item2 != null ? customerAndAddress.Item2.SingleOrDefault(o => o.Type == "Main") : null;
var customerDetails = new CustomerDetails
{
FirstName = customerAndAddress.Item1.Name,
LastName = customerAndAddress.Item1.Surname,
Title = customerAndAddress.Item1.Title,
Dob = customerAndAddress.Item1.Dob,
EmailAddress = customerAndAddress.Item1.Email,
Gender = customerAndAddress.Item1.Gender,
PrimaryPhoneNo = string.Format("{0}", customerAndAddress.Item1.Phone)
};
if (mainAddress != null)
{
customerDetails.AddressLine1 =
!string.IsNullOrWhiteSpace(mainAddress.HouseName)
? mainAddress.HouseName
: mainAddress.HouseNumber;
customerDetails.AddressLine2 =
!string.IsNullOrWhiteSpace(mainAddress.Street)
? mainAddress.Street
: null;
customerDetails.AddressLine3 =
!string.IsNullOrWhiteSpace(mainAddress.Town) ? mainAddress.Town : null;
customerDetails.AddressLine4 =
!string.IsNullOrWhiteSpace(mainAddress.County)
? mainAddress.County
: null;
customerDetails.PostCode = mainAddress.PostCode;
}
...
return customerDetails;
}
out 매개변수는 반환해야 할 값이 몇 개뿐일 때 유용하지만 반환해야 할 값이 4, 5, 6 이상이 발생하기 시작하면 사용하기 어려워질 수 있습니다.여러 값을 반환하는 또 다른 옵션은 사용자 정의 클래스/구조를 만들고 반환하거나 Tuple을 사용하여 메서드에서 반환해야 하는 모든 값을 패키지화하는 것입니다.
클래스/구조를 사용하여 값을 반환하는 첫 번째 옵션은 간단합니다.다음과 같이 유형(이 예에서는 구조)을 만듭니다.
public struct Dimensions
{
public int Height;
public int Width;
public int Depth;
}
Tuple을 사용하는 두 번째 옵션은 사용자 정의 개체를 사용하는 것보다 훨씬 더 우아한 솔루션입니다.튜플은 다양한 유형의 값을 여러 개 저장하도록 생성할 수 있습니다.또한 Tuple에 저장하는 데이터는 변경할 수 없습니다. 생성자 또는 정적 Create 메서드를 통해 Tuple에 데이터를 추가하면 해당 데이터를 변경할 수 없습니다.튜플은 최대 8개의 개별 값을 포함하여 사용할 수 있습니다.8개 이상의 값을 반환해야 하는 경우 특수 Tuple 클래스를 사용해야 합니다.튜플 클래스 값이 8개를 초과하는 튜플을 만드는 경우 정적 Create 메서드를 사용할 수 없습니다. 대신 클래스의 생성자를 사용해야 합니다.다음은 10개의 정수 값으로 구성된 Tuple을 만드는 방법입니다.
var values = new Tuple<int, int, int, int, int, int, int, Tuple<int, int, int>> (
1, 2, 3, 4, 5, 6, 7, new Tuple<int, int, int> (8, 9, 10));
물론 내장된 각 튜플의 끝에 튜플을 계속 추가하여 필요한 크기의 튜플을 만들 수 있습니다.
시제품 제작에만 해당 - 튜플은 의미가 없습니다.그것들을 사용하는 것은 편리하지만 그것은 오직 지름길입니다!프로토타입의 경우 - 좋습니다.나중에 이 코드를 삭제하십시오.
쓰기는 쉽고 읽기는 어렵습니다.그것은 클래스, 내부 클래스, 익명 클래스 등에 비해 눈에 보이는 이점이 없습니다.
저는 C#7에서 동일한 문제를 해결하기 위해 3가지 방법을 시도했고 Tuples의 사용 사례를 찾았습니다.
웹 프로젝트에서 동적 데이터로 작업하는 것은 매핑 등을 할 때 때때로 번거로울 수 있습니다.
나는 투플이 항목 1, 항목 2, 항목 N에 자동 매핑된 방식을 좋아하는데, 이것은 당신이 색인 외 항목에 걸릴 수 있는 배열 인덱스를 사용하거나 속성 이름의 철자를 틀릴 수 있는 익명 유형을 사용하는 것보다 더 강력해 보입니다.
Tuple을 사용하는 것만으로도 DTO가 무료로 생성된 것 같고, 별도의 DTO를 생성하지 않고도 정적 타이핑에 가까운 항목 N을 사용하여 모든 속성에 액세스할 수 있습니다.
using System;
namespace Playground
{
class Program
{
static void Main(string[] args)
{
var tuple = GetTuple();
Console.WriteLine(tuple.Item1);
Console.WriteLine(tuple.Item2);
Console.WriteLine(tuple.Item3);
Console.WriteLine(tuple);
Console.WriteLine("---");
var dyn = GetDynamic();
Console.WriteLine(dyn.First);
Console.WriteLine(dyn.Last);
Console.WriteLine(dyn.Age);
Console.WriteLine(dyn);
Console.WriteLine("---");
var arr = GetArray();
Console.WriteLine(arr[0]);
Console.WriteLine(arr[1]);
Console.WriteLine(arr[2]);
Console.WriteLine(arr);
Console.Read();
(string, string, int) GetTuple()
{
return ("John", "Connor", 1);
}
dynamic GetDynamic()
{
return new { First = "John", Last = "Connor", Age = 1 };
}
dynamic[] GetArray()
{
return new dynamic[] { "John", "Connor", 1 };
}
}
}
}
언급URL : https://stackoverflow.com/questions/2745426/practical-example-where-tuple-can-be-used-in-net-4-0
'programing' 카테고리의 다른 글
이클립스로 GitHub 프로젝트 가져오기 (0) | 2023.05.18 |
---|---|
리눅스에서 어떻게 PID 대신 이름으로 프로세스를 죽일 수 있습니까? (0) | 2023.05.18 |
Git: "손상된 느슨한 개체" (0) | 2023.05.18 |
C#에 대해 가장 좋아하는 확장 방법은 무엇입니까? (codeplex.com/extensionoverflow) (0) | 2023.05.18 |
데이터가 Null입니다.이 메서드 또는 속성은 Null 값에 대해 호출할 수 없습니다. (0) | 2023.05.18 |