[C#]Tuple Class

function想要回傳多個值的好用類別

舊方法和缺點

  • 自訂class或struct,將想回傳的值包在裡面
    • 有時不是強烈內聚關係,只是單純放在一起,其實並不妥當
    • 有時只會被這個方法使用,無法重用
  • 透過物件的成員,經過方法後的狀態轉變,再取用
    • 若為static方法,可能有thread-safe問題
    • 回傳值的生命週期應該只在這個方法內
  • 使用 out 或 ref,在呼叫時先傳進來
    • 方法外面要先宣告,方法裡面要重新給值
    • 當回傳多個值會相當礙眼

Tuple Class(.NET Framework 4.0)

Tuple Class連結

簡單範例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
namespace App.Domain.Model
{
using System;

public class MemberInfo
{
public int MemberID { get; set; }

public string NickName { get; set; }

public string Email { get; set; }
}
}

namespace App.Domain.Repository
{
public interface IMemberInfoRepository
{
Tuple<Exception, MemberInfo> FindMemberInfo(int memberID);
}
}

namespace App.Persistent.SQL
{
public class MemberInfoRepository : IMemberInfoRepository
{
private string connectionString;

public MemberInfoRepository(string connectionString)
{
this.connectionString = connectionString;
}

public Tuple<Exception, MemberInfo> FindMemberInfo(int memberID)
{
try
{
using (var conn = new SqlConnection(this.connectionString))
{
var result = conn.QueryFirstOrDefault<MemberInfo>(
"SPName",
new
{
MemberID = memberID
},
commandType: CommandType.StoredProcedure);

return Tuple.Create<Exception, MemberInfo>(null, result);
}
}
catch (Exception ex)
{
return Tuple.Create<Exception, MemberInfo>(ex, null);
}
}
}
}

namespace App.Persistent.Tests
{
[TestClass]
public class MemberInfoRepositoryTests
{
private IMemberInfoRepository memberInfoRepo;

[TestInitialize]
public void Initialize()
{
this.memberInfoRepo = new MemberInfoRepository(ConfigHelper.SQLConnectionString);
}

[TestMethod]
public void FindMemberInfo_Success_Test()
{
// Arrange
int memberID = 100000;

// Act
var result = this.memberInfoRepo.FindMemberInfo(memberID);

// Assert
Assert.IsNull(result.Item1);
Assert.IsNotNull(result.Item2);
Assert.AreEqual(memberID, result.Item2.MemberID);
}
}
}

規範建議

  • 可讀性不佳(C# 7.0可自訂名稱): Tuple的Item不超過3個
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
namespace App.Persistent.SQL
{
public class MemberInfoRepository : IMemberInfoRepository
{
private string connectionString;

public MemberInfoRepository(string connectionString)
{
this.connectionString = connectionString;
}

public (Exception ex, MemberInfo memberInfo) FindMemberInfo(int memberID)
{
try
{
using (var conn = new SqlConnection(this.connectionString))
{
var result = conn.QueryFirstOrDefault<MemberInfo>(
"SPName",
new
{
MemberID = memberID
},
commandType: CommandType.StoredProcedure);

return (null, result);
}
}
catch (Exception ex)
{
return (ex, null);
}
}
}
}

namespace App.Persistent.Tests
{
[TestClass]
public class MemberInfoRepositoryTests
{
private IMemberInfoRepository memberInfoRepo;

[TestInitialize]
public void Initialize()
{
this.memberInfoRepo = new MemberInfoRepository(ConfigHelper.SQLConnectionString);
}

[TestMethod]
public void FindMemberInfo_Success_Test()
{
// Arrange
int memberID = 100000;

// Act
var result = this.memberInfoRepo.FindMemberInfo(memberID);

// Assert
Assert.IsNull(result.ex);
Assert.IsNotNull(result.memberInfo);
Assert.AreEqual(memberID, result.memberInfo.MemberID);
}
}
}
  • Summary註解中要說明各個Item代表的意義
  • 在Persistent中,Item1為Exception,Item2以後為回傳值
-------------The End-------------