質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

2回答

2260閲覧

コードの評価をしてください その2

ranran

総合スコア85

VB

VB(ビジュアルベーシック)はマイクロソフトによってつくられたオブジェクト指向プログラミング言語のひとつで、同社のQuickBASICが拡張されたものです。VB6の進化版といわれています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2015/03/28 14:17

編集2015/03/28 20:16

お世話になります。

拡張性の高いクラスというものを作りたく
ジェネリックを使用しクラスを作成してみました。

このような作り方じゃだめ
こうするべき
これを参考にしたほうがいい
等ありましたらご教授ください

どうかよろしくお願いいたします。

追記1
1、2言のコメントでも頂けましたら幸いです。
今後のプログラミングでいかしていけるよう心に留めます。

lang

1概要 2 リスト内要素 2回以上連続する場合1回とする 3クラス 4 Class ConvertList(Of T) 5コンストラクタ 6 Sub New(ByVal list As List(Of T), ByVal convertType As Type, Optional ByVal itemName As String = Nothing) 7メソッド 8 Function GetList() As List(Of T) 9 10[使用例] 111. 12 Dim list as new List(of DataRow) 13 Dim row as DataRow = nothing 14 Dim column as new DataColumn("F_Tmp",Type.GetType("System.String")) 15 Dim table as DataTable("table1") 16 17 table.Columns.Add(column) 18 19 For i = 0 to 5 20 row = table.NewRow 21 row.Item("F_Tmp") = "aaa" 22 list.Add(row) 23 next 24 25 For i = 0 to 10 26 row = table.NewRow 27 row.Item("F_Tmp") = "bbb" 28 list.Add(row) 29 next 30 31 For i = 0 to 3 32 row = table.NewRow 33 row.Item("F_Tmp") = "ccc" 34 list.Add(row) 35 next 36 37 Dim cls As New ConvertList(Of DataRow)(list, ConvertList(Of DataRow).Type.NotConsecutive, "F_Tmp") 38 39 '列名 F_Tmp を対象とし、連続しているDataRowを1つにする 40 list = cls.GetList() 41 42 'リストの中身はaaa,bbb,ccc1つずつになる 43 442. 45 Dim list As New List(Of String) From {"one", "one", "two", "three", "three", "three"} 46 47 Dim cls As New ConvertList(Of DataRow)(list, ConvertList(Of DataRow).Type.NotConsecutive) 48 49 'ToStringを対象とし、連続しているStringを1つにする 50 list = cls.GetList() 51 52 'リストの中身はone,two,three1つずつになる 53

以下本体

lang

1 2''' <summary> 3''' リストを変換する 4''' </summary> 5''' <remarks></remarks> 6Public Class ConvertList(Of T) 7 8#Region "定義" 9 10 ''' <summary> 11 ''' 変換タイプ 12 ''' </summary> 13 ''' <remarks></remarks> 14 Enum Type 15 '連続しない 16 NotConsecutive 17 End Enum 18 19#End Region 20 21#Region "変数" 22 23'リスト 24Private Property list As List(Of T) 25 26'対象アイテム 27Private Property itemName As String 28 29'変換タイプ 30Private Property convertType As Type 31 32'変換クラス 33Private Property cls As IConvertEnumrable(Of T) 34 35#End Region 36 37#Region "コンストラクタ" 38 39''' <summary> 40''' コンストラクタ 41''' </summary> 42''' <param name="list">変換対象のリスト</param> 43''' <param name="convertType">変換タイプ</param> 44''' <param name="itemName">リスト内各要素 比較対象</param> 45''' <remarks></remarks> 46Public Sub New(ByVal list As List(Of T), ByVal convertType As Type, Optional ByVal itemName As String = Nothing) 47 Me.list = list 48 Me.itemName = itemName 49 Me.convertType = convertType 50 51 '変換タイプの変換クラスをインスタンス化 52 Call SetConvertType() 53End Sub 54 55#End Region 56 57#Region "公開メソッド" 58 59 ''' <summary> 60 ''' 行返す 61 ''' </summary> 62 ''' <returns></returns> 63 ''' <remarks></remarks> 64Public Function GetList() As List(Of T) 65 66 '行取得 67 Return Me.cls.GetEnumerable().ToList() 68 69End Function 70 71#End Region 72 73#Region "内部メソッド" 74 75 ''' <summary> 76 ''' 変換タイプに一致するクラスをインスタンス化 77 ''' </summary> 78 ''' <remarks></remarks> 79 Private Sub SetConvertType() 80 81 Select Case Me.convertType 82 Case Type.NotConsecutive 83 Me.cls = New NotConsecutive(Of T)() 84 Me.cls.SetEnumerable(Me.list, Me.itemName) 85 End Select 86 87 End Sub 88 89#End Region 90 91End Class 92

lang

1''' <summary> 2''' 変換インターフェイス 3''' </summary> 4''' <remarks></remarks> 5Public Interface IConvertEnumrable(Of T) 6 7 'リストを受け取る 8 Sub SetEnumerable(ByVal list As IEnumerable(Of T), ByVal itemName As String) 9 10 'リストを返す 11 Function GetEnumerable() As IEnumerable(Of T) 12 13 '比較対象となるアイテム取得 14 Function GetItem(ByVal i As Integer) As String 15 16End Interface 17 18 19 20''' <summary> 21''' 変換クラス 22''' </summary> 23''' <remarks></remarks> 24Class NotConsecutive(Of T) 25 Implements IConvertEnumrable(Of T) 26 27#Region "変数" 28 29 'リスト 30 Public Property list As List(Of T) 31 '対象アイテム 32 Public Property itemName As String 33 34#End Region 35 36#Region "公開メソッド" 37 38 ''' <summary> 39 ''' リストを受け取る 40 ''' </summary> 41 ''' <param name="list"></param> 42 ''' <param name="itemName"></param> 43 ''' <remarks></remarks> 44 Public Sub SetEnumerable(list As IEnumerable(Of T), ByVal itemName As String) Implements IConvertEnumrable(Of T).SetEnumerable 45 46 Me.list = list 47 Me.itemName = itemName 48 49 End Sub 50 51 ''' <summary> 52 ''' リストを返す 53 ''' </summary> 54 ''' <returns></returns> 55 ''' <remarks></remarks> 56 Public Iterator Function GetEnumerable() As IEnumerable(Of T) Implements IConvertEnumrable(Of T).GetEnumerable 57 58 For i = 0 To Me.list.Count - 1 59 60 If i <> Me.list.Count - 1 Then 61 '最後のインデックス以外 62 While GetItem(i) = GetItem(i + 1) 63 '連続する値は返さない 64 Continue For 65 End While 66 End If 67 68 '連続時は最後の値を返す 69 Yield Me.list(i) 70 Next 71 72 End Function 73 74 ''' <summary> 75 ''' アイテム取得 76 ''' </summary> 77 ''' <param name="i"></param> 78 ''' <returns></returns> 79 ''' <remarks></remarks> 80 Public Function GetItem(ByVal i As Integer) As String Implements IConvertEnumrable(Of T).GetItem 81 Dim item As Object = Me.list(i) 'インデックスの位置のアイテム 82 Dim ret As String = Nothing '戻り値 83 84 If Me.itemName Is Nothing Then 85 'アイテムの指定がなかった場合 86 ret = item.ToString() 87 Else 88 'アイテムの指定があった場合 89 Select Case GetType(T) 90 '- DataRowの場合 91 Case GetType(DataRow) 92 ret = item.item(itemName) 93 94 End Select 95 End If 96 97 '比較対象を返す 98 Return ret 99 End Function 100 101#End Region 102 103End Class 104

追記2
変換クラスである「NotConsecutive」において
連続を省くという処理が分離されておらず
良くないコードと感じましたので修正いたします。

lang

1''' <summary> 2''' 変換クラス 3''' </summary> 4''' <remarks></remarks> 5Class NotConsecutive(Of T) 6 Inherits ConvertEnumrable(Of T) 7 8#Region "公開メソッド" 9 10 ''' <summary> 11 ''' 連続する値は返さない 12 ''' </summary> 13 ''' <param name="i"></param> 14 ''' <returns>T 返却対象 F 返却対象でない</returns> 15 ''' <remarks>引数はリストの各インデックスである</remarks> 16 Protected Overrides Function IsGetEnumrable(ByVal i As Integer) As Boolean 17 18 If i <> Me.list.Count - 1 Then 19 '最後のインデックス以外 20 While GetItem(i) = GetItem(i + 1) 21 '連続する値は返さない 22 Return False 23 End While 24 End If 25 26 Return True 27 28 End Function 29 30#End Region 31 32End Class

あわせてインターフェース、変換クラスのベースを作成します。
(インターフェースにふさわしくないメソッドがあり修正いたしました。)

lang

1''' <summary> 2''' 変換インターフェイス 3''' </summary> 4''' <remarks></remarks> 5Public Interface IConvertEnumrable(Of T) 6 7 'リストを受け取る 8 Sub SetEnumerable(ByVal list As IEnumerable(Of T), ByVal itemName As String) 9 10 'リストを返す 11 Function GetEnumerable() As IEnumerable(Of T) 12 13End Interface 14 15 16''' <summary> 17''' 変換クラス 18''' </summary> 19''' <typeparam name="T"></typeparam> 20''' <remarks></remarks> 21Public MustInherit Class ConvertEnumrable(Of T) 22 Implements IConvertEnumrable(Of T) 23 24#Region "変数" 25 26 'リスト 27 Protected Property list As List(Of T) 28 '対象アイテム 29 Protected Property itemName As String 30 31#End Region 32 33#Region "公開メソッド" 34 35 ''' <summary> 36 ''' リストを受け取る 37 ''' </summary> 38 ''' <param name="list"></param> 39 ''' <param name="itemName"></param> 40 ''' <remarks></remarks> 41 Public Sub SetEnumerable(list As IEnumerable(Of T), ByVal itemName As String) Implements IConvertEnumrable(Of T).SetEnumerable 42 43 Me.list = list 44 Me.itemName = itemName 45 46 End Sub 47 48 ''' <summary> 49 ''' リストを返す 50 ''' </summary> 51 ''' <returns></returns> 52 ''' <remarks></remarks> 53 Public Iterator Function GetEnumerable() As IEnumerable(Of T) Implements IConvertEnumrable(Of T).GetEnumerable 54 55 For i = 0 To Me.list.Count - 1 56 57 '返却対象でない場合スキップ 58 If IsGetEnumrable(i) = False Then Continue For 59 60 '値を返す 61 Yield Me.list(i) 62 Next 63 64 End Function 65 66#End Region 67 68#Region "内部メソッド" 69 70 ''' <summary> 71 ''' 返却対象の値であるか確認 72 ''' </summary> 73 ''' <param name="i"></param> 74 ''' <returns>T 返却対象 F 返却対象でない</returns> 75 ''' <remarks>引数はリストの各インデックスである</</remarks> 76 Protected MustOverride Function IsGetEnumrable(ByVal i As Integer) As Boolean 77 78 79 ''' <summary> 80 ''' アイテム取得 81 ''' </summary> 82 ''' <param name="i"></param> 83 ''' <remarks></remarks> 84 Protected Function GetItem(ByVal i As Integer) As String 85 Dim item As Object = Me.list(i) 'インデックスの位置のアイテム 86 Dim ret As String = Nothing '戻り値 87 88 If Me.itemName Is Nothing Then 89 'アイテムの指定がなかった場合 90 ret = item.ToString() 91 Else 92 'アイテムの指定があった場合 93 Select Case GetType(T) 94 '- DataRowの場合 95 Case GetType(DataRow) 96 ret = item.item(itemName) 97 98 End Select 99 End If 100 101 '比較対象を返す 102 Return ret 103 End Function 104 105#End Region 106 107End Class

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

あまり構造化が得意ではないC#PGですが何点か。

  1. そもそも設計としておかしい。

おそらく、実現しようとしている機能自体は本題じゃないからなんだと思うのですが
むりやり面倒なことをしていなぁ・・・と感じてしまいます。
IsGetEnumrableメソッドをデリゲートで受け付けてリストに反映してくれる拡張メソッドのほうが汎用性が高いのではないでしょうか?(ジェネリック関係なくなってしまうのでとりあえずこれはそういう方法がある程度にどうぞ)

  1. 内部で作成されるインスタンスについて

「汎用性」が何を指しているかわかりませんが、「NotConsecutive」クラスはConvertListの外で定義されているのにConvertListの内部でインスタンスを作成しているのが気になります。
やるならType列挙型で動作を制限するより、動作そのものを外部から受け取るのが良いと思います。

  1. 型依存

ConvertEnumrable.GetItemメソッドの内部で型による分岐が発生している為、果たしてこれは汎用性があるのか疑問です。
型依存するならば依存することを利用者に明示できるように型パラメータの制約で表現したほうが良いと思います。コメントもないですし、あえて隠しているならばいじわるです。

あとがき:
正直何をどこまでしたいのかわかりませんでしたが、手段のために目的を設定しているなぁという印象です。作者さんが「こういうものです」といえば「あ、はい」としかいえませんが;
「汎用性」というものをどこまで求めていらっしゃるかによりますが、少なくとも上記2と3の理由から汎用的とは言えないと感じております。
汎化するのと汎用性を求めるのは違うという認識の元でですが、「汎用性」を確保する為にクラスを設計するという方はあまり居ないのではないでしょうか。
あまりお役に立てなくて申し訳ありません。

投稿2015/03/31 06:54

Ryzna

総合スコア85

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Ryzna

2015/03/31 08:17

蛇足かもしれませんが、型パラメータと汎用性についての私見です。 型パラメータ: 型パラメータは制約の有無を含めて型を明確にするために用いるべきと考えます。 制約をしないのであれば一貫して制限を設けない。 特定の結果をメンバがほしいならばそれが実装されていることを保障する特定のクラスなりインターフェイスなりを継承していることを制約とするべきと考えます。(自作が必要ならばそれも含めて) 汎用性: 今回のパターンでは型毎に挙動が変わるならばそれは同一クラスにするべきではないと考えます。 「ConvertList クラス は AリストをBリストに変換(投影)する際の基本的な構造・フローを定義するだけにとどめ、そこから派生してリストAやBの具体的な仕様を盛り込んだり、AからBに変換する実装をする」ほうがConvertListクラスそのものについては「汎用性」が出てくるのではないでしょうか? 私はこれが「汎化と特化」の一部だと考えています。(間違ってたら指摘ください;;)
Ryzna

2015/03/31 08:19

楽する為の設計するのが一番いい気がします。
ranran

2015/03/31 11:03

回答いただけたかた全員に対してになりますが 面倒くさい質問に答えて頂けたこと、 心より感謝申し上げます。 ご指摘を真摯に受け止め 反省とともにより良いコードを記述できるよう学ばせて頂きます。 > 1. そもそも設計としておかしい。 ジェネリックを使用するため無理やり作成した面があります(^^; 確かに拡張メソッドを使ったほうがシンプルそうです ジェネリックを意識しすぎたあまり、 拡張メソッドまで気が回りませんでした。 > 2. 内部で作成されるインスタンスについて 悩んだ個所であるのですが、 クラス内に列挙型で動作定義したほうが、 インテリセンスの補完により扱いやすいかなと思いました。 ですがよくよく考えてみますと、 その度にクラスを変更してビルドして,,,となると非効率ですね。 今後、動作が増えるような場合には 外部より貰うようにしようと思います。 > 3. 型依存 その通りです、 コーディングしながら汚い書き方と思いました。 ですがこれが自身の限界です。 これ以外に書き方が思いつきませんでした。 リスト内の型によって datarowの場合、Item("")を対象に Stringの場合、toString()を対象に のようにしたい場合どのようにするべきでしょうか? それとも前提がおかしいのでしょうか? > あとがき 目的としましては、 自身の日ごろのコーディングはその場凌ぎのものが多いです。 そしてどんどん似たようなコードが増えていきます。 修正が大変になります。 できるだけ拡張性が高く、今後の修正にも対応できるような コードを記述したく今回は「ジェネリック」にスポットを当てました。 > あまりお役に立てなくて申し訳ありません。 大変勉強になります。 私自身、痛感しておりますが頭が固く 日頃より無駄の多いコードになっていると感じております。 よりよい技術者になれるよう頑張りたいと思います。 追記のコメントありがとうございます。 私用によりパソコンの前より離れますので、 今晩改めて追記に対するコメント致します。 今後ともよろしくお願いいたします。
ranran

2015/03/31 14:44

> 型パラメータは制約の有無を含めて型を明確にするために用いるべき > クラスなりインターフェイスなりを継承していることを制約とするべき なるほどと思わされました! 根本的にジェネリックの認識が間違っていたようです。 > 「汎化と特化」 普段意識しておりませんでした(^^; ジェネリックについてもそうですが、 使い方、定義を自分の中でしっかりまとめようと思います。 本当にありがとうございました!
guest

0

ベストアンサー

拡張性というか汎用性を持たせたいのかなと思ったので、
私なりに汎用性を得ていく過程をなんとなくで書いてみました。
C#で書きます。すみません。

あなたはList<int>に対して連続ダブりを除去したいなと思いました。
そこで例えばこういうコードを書きます。

lang

1var source = new List<int>(){1,2,2,3,3,3,1}; 2var result = new List<int>(); 3result.Add(source[0]); 4for (int i = 1; i < source.Count; i++) 5{ 6 if (source[i] != source[i - 1])) 7 result.Add(source[i]); 8} 9 //expected:1,2,3,1

その後あなたは別なところでもこの処理をしたいなと思いました。
そこで例えば拡張メソッドにします。

lang

1var source = new List<int>(){1,2,2,3,3,3,1}; 2var result = source.DistinctUntilChanged();

lang

1 2public static List<int> DistinctUntilChanged<int>(this List<int> source) 3{ 4 var result = new List<int>(); 5 result.Add(source[0]); 6 for (int i = 1; i < source.Count; i++) 7 { 8 if (source[i] != source[i - 1])) 9 result.Add(source[i]); 10 } 11 return result; 12}

(まあこれだと要素数が0,1の時例外投げますが。)
更にその後あなたはint以外でも同じことをやりたくなりました。
そこでジェネリックを使うことにしました。

lang

1 2public static List<T> DistinctUntilChanged<T>(this List<T> source) where T : IEquatable<T> 3{ 4 var result = new List<int>(); 5 result.Add(source[0]); 6 for (int i = 1; i < source.Count; i++) 7 { 8 if (!source[i].Equals(source[i - 1])) 9 result.Add(source[i]); 10 } 11 return result; 12}

更にさらに
...
...

長い上に質問の答えになっていませんが、
汎用性は必要になった時に必要なだけ拡張すればいいと思います。

投稿2015/03/31 09:13

編集2015/03/31 09:19
ozwk

総合スコア13521

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ozwk

2015/03/31 13:15

あと細かいことですが ・Convert~クラス、インターフェース 一瞬メソッド名かと思いました。 クラス名なら EnumerableConverter などと名詞形にするといいと思います。 ・IsGetEnumrable Isの後にGetが来るのもどうなんでしょうね。 CanGet~とかいいんじゃないでしょうか。 まあ、「日本人しか読まないからいいんだよ!」と思うかもしれませんが。
ranran

2015/03/31 15:30

回答いただけたかた全員に対してになりますが 面倒くさい質問に答えて頂けたこと、 心より感謝申し上げます。 ご指摘を真摯に受け止め 反省とともにより良いコードを記述できるよう学ばせて頂きます。 > 汎用性は必要になった時に必要なだけ拡張すればいいと思います。 拡張の過程をみさせていただきまさにその通りだと思いました! すごいです、綺麗です! このようにコードを考えていけばよいのですね とても参考になりました! 自身でもすらすら記述できるよう 頭に刻み付けます。 > あと細かいことですが > まあ、「日本人しか読まないからいいんだよ!」と思うかもしれませんが。 その中でもコメントいただけた、 ozwkさんに感謝を。 「名詞形」をまったく意識しておりませんでした、 今後、クラス名のつけ方、動詞、助動詞 意識していきます! 今後とも気づかれた点ありましたら是非 ご指摘ください♪ 本当にありがとうございました! 連続除去メソッド、拡張メソッド、ジェネリックの 遷移がとても分かりやすかったです。 ベストアンサーと致します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問