#質問
以下が改善中の最新のコードです。
C#
1 2// データを取得 3interface IGetData<out T> 4{ 5 Tuple<bool, TParsed> ParseData(TRaw data); 6} 7 8// データを検証 9interface IValidateData<in T> 10{ 11 // 必ずGetできる。失敗するのは例外的状況 12 T GetData(); 13} 14 15// データを変換 16interface IParseData<in TRaw, TParsed> 17{ 18 // 与えるrawによって失敗。成功した場合Dataに結果が入る。 19 bool ValidateData(T data); 20} 21 22// データをマッピング 23// 必ずMapできる。失敗するのは例外的状況 24// 失敗したら予期しないエラーにする? 25interface IMapData<in TRaw, out TMapped> 26{ 27 TMapped MapData(TRaw raw); 28} 29 30// データを送信 31interface ISendData<in T> 32{ 33 // 必ずSendできる。失敗するのは例外的状況 34 void SendData(T data); 35} 36 37// アプリケーション例外のベースとなる抽象例外クラス 38public abstract class MyNantokaApplicationException : Exception 39{ 40 public IFixedLog Log { get; } 41 42 protected MyNantokaApplicationException(IFixedLog log) 43 : base() 44 { 45 this.Log = log; 46 } 47 48 //... 49} 50 51// GetDataがGetに失敗したときに出す例外とする 52public class GetDataException : MyNantokaApplicationException 53{ 54 //... 55} 56 57// SendDataがSendに失敗したときに出す例外とする 58public class SendDataException : MyNantokaApplicationException 59{ 60 //... 61} 62 63// MapDataがMapに失敗したときに出す例外とする 64// 失敗したら予期しないエラーのほうがいい? 65public class MapException : MyNantokaApplicationException 66{ 67 //... 68} 69 70// GetParseSendFlowがデータの変換に失敗したときに出す例外とする 71public class ParseFailedException : MyNantokaApplicationException 72{ 73 //... 74} 75 76// オブジェクトの生成に失敗したときに出す例外とする 77public class ConstructorException : MyNantokaApplicationException 78{ 79 //... 80} 81 82class Program 83{ 84 static int Main() 85 { 86 var logger = new FixedLoggerToFile(); 87 try 88 { 89 // 本当はリソースを保持したらだめ 90 using (var sender = new PlainFileSender(@"C:\...")) // Send) 91 { 92 var getter = new FileDataGetter("..."); // Get 93 94 var validator = new XXXXLogDataValidatorWithLog(logger); 95 var mapper = new XXXSimpleMapper(); 96 var parser = new CollectionParser<string, Something>(validator, mapper, logger); // Parse 97 98 var test = new GetParseSendFlow<IEnumerable<string>, IEnumerable<Something>>(getter, parser, sender); // 合体 99 test.Do(); // 処理実行 100 } 101 102 return 0; // 正常終了 103 } 104 catch (MyNantokaApplicationException exception) // アプリケーション例外の場合は 105 { 106 var log = exception.Log; // 例外からLogを取り出す 107 if (log != null) 108 logger.Log(log); // ログを出力 109 return -1; 110 } 111 catch // 予期しない例外の場合は 112 { 113 var log = UnexpectedErrorLog.Instance; 114 logger.Log(log); 115 return -1; 116 } 117 } 118} 119 120class GetParseSendFlow<TData, TParsed> 121{ 122 //... 123 124 public GetParseSendFlow(IGetData<TData> getter, IParseData<TData, TParsed> parser, ISendData<TParsed> sender) 125 { 126 //... 127 } 128 129 public void Do() 130 { 131 var raw = _getter.GetData(); // GetDataExceptionが起きても何もできないので素通し 132 133 var parseResult = _parser.ParseData(raw); // ParseDataは例外を出さない 134 135 if (!parseResult.Item1)// parseが失敗した場合は 136 { 137 //var log = ParseFailedAndInterruptErrorLog.Instance; // お手上げなのでぶん投げる 138 throw new ParsedFailedException(null); // 要件を満たすためにとりあえずnull 139 } 140 141 _sender.SendData(parseResult.Item2); // SendDataExceptionが起きても何もできないので素通し 142 } 143} 144 145// ファイルから文字列のコレクションを取得するIGetDataの実装 146public class FileDataGetter : IGetData<IEnumerable<string>> 147{ 148 //... 149 150 public FileDataGetter(string path /** , string ... **/) 151 { 152 _path = path; 153 } 154 155 public IEnumerable<string> GetData() 156 { 157 StreamReader reader = null; 158 NetworkConnection networkConnection = null; 159 160 try 161 { 162 try 163 { 164 // ネットワークに接続 165 } 166 catch 167 { 168 throw new GetDataException(ConnectToNetworkForFileErrorLog.Instance); // GetDataExceptionをスロー 169 } 170 171 try 172 { 173 // ファイルオープン 174 reader = new StreamReader(_path); 175 } 176 catch 177 { 178 throw new GetDataException(FileOpenErrorLog.Instance); // GetDataExceptionをスロー 179 } 180 181 var list = new List<string>(); 182 //... 183 return list; 184 } 185 finally 186 { 187 reader?.Dispose(); 188 networkConnection?.Dispose(); 189 } 190 } 191} 192 193// コレクションのデータを変換するIParseDataの実装 194class CollectionParser<TRawItem, TMappedItem> : IParseData<IEnumerable<TRawItem>, IEnumerable<TMappedItem>> 195{ 196 //... 197 198 public CollectionParser( 199 IValidateData<TRawItem> validator, 200 IMapData<TRawItem, TMappedItem> mapper, 201 IFixedLogger logger) 202 { 203 this._validator = validator; 204 this._mapper = mapper; 205 this._logger = logger; 206 } 207 208 public Tuple<bool, IEnumerable<TMappedItem>> ParseData(IEnumerable<TRawItem> rawItems) 209 { 210 // 変換の成否に関する戻り値設定に使う 211 var inputItemsCount = 0; 212 213 // 検証と変換に成功したもののみで絞込 214 var parseResult = rawItems.Select( 215 rawItem => 216 { 217 // 生データコレクションカウント 218 inputItemsCount++; 219 220 if (_validator.ValidateData(rawItem)) // 検証してみる 221 { 222 // 検証OKならマッピングしてみる 223 try 224 { 225 var mapped = this._mapper.MapData(rawItem); 226 return new { Data = mapped, Result = true }; 227 } 228 catch (MapException ex) 229 { 230 _logger.Log(ex.Log); // 失敗したらエラーログ 231 } 232 } 233 // 検証失敗やマッピングで例外の場合は失敗を返す 234 return new { Data = default(TMappedItem), Result = false }; 235 }).Where(mappingResult => mappingResult.Result).Select(mappingResult => mappingResult.Data).ToList(); 236 237 // 得られたコレクションの長さで判定 238 return new Tuple<bool, IEnumerable<TMappedItem>>(parseResult.Count == inputItemsCount, parseResult); 239 } 240} 241 242// 特定のソフトが出力するログを検証し、エラーログも出力するIValidateの実装 243class XXXXLogDataValidatorWithLog : IValidateData<string> 244{ 245 private readonly IFixedLogger _logger; 246 247 public XXXXLogDataValidatorWithLog(IFixedLogger logger) 248 { 249 this._logger = logger; 250 } 251 252 public bool ValidateData(string data) 253 { 254 var result = data == string.Empty; 255 // 失敗したらログを出力 256 if (!result) 257 { 258 _logger.Log(UnavailableDataDetectedErrorLog.GetInstance(data, "文字列が空文字")); 259 } 260 261 return result; 262 } 263} 264 265// 特定のソフトが出力するログをオブジェクトに変換するIMapの実装 266class XXXSimpleMapper : IMapData<string, Something> 267{ 268 public Something MapData(string raw) 269 { 270 string name; 271 string message; 272 273 try 274 { 275 name = raw.Substring(0, 10).TrimStart(); 276 } 277 catch 278 { 279 // ここや 280 throw new SimpleMapExeption("名前が変換できない", raw); 281 } 282 283 try 284 { 285 message = raw.Substring(10); 286 } 287 catch 288 { 289 // ここは、MapExceptionではなく、予期しないエラーになるべきか? 290 // あるいは、ここでログを出力する? 291 // その場合返すものがなくなる 292 // IParseDataにかえて、ここでログをはきfalseを返す? 293 // そもそもIMapいる? 294 throw new SimpleMapExeption("メッセージが変換できない", raw); 295 } 296 297 return new Something(name, message); 298 } 299} 300 301#endregion 302 303#region ISendDataの実体 304// データをファイルに送信するISendDataの実装 リソースを保持するのでよくない 305class PlainFileSender : ISendData<IEnumerable<Something>>, IDisposable 306{ 307 private readonly StreamWriter _writer; 308 309 public PlainFileSender(string path) 310 { 311 try 312 { 313 this._writer = new StreamWriter(path, true); 314 } 315 catch 316 { 317 throw new ConstructorException(FileOpenErrorLog.Instance); 318 } 319 320 } 321 322 public void SendData(IEnumerable<Something> data) 323 { 324 try 325 { 326 // データをテキストファイルに追加 327 } 328 catch 329 { 330 throw new SendDataException(FileAppendErrorLog.Instance); 331 } 332 } 333 334 public void Dispose() 335 { 336 this._writer?.Dispose(); 337 } 338} 339 340#endregion 341```質問は以下になります。 3420. MapDataで発生した例外は予期しないエラーとするべきか意見をください。 343よろしくお願いします。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/01/20 08:18
2017/01/20 08:42
2017/01/20 09:32
2017/01/20 10:11
2017/01/21 02:13
2017/01/21 16:49 編集
2017/01/21 05:58
2017/01/21 07:30 編集
2017/01/21 13:04 編集
2017/01/21 17:18 編集
2017/01/22 01:12
2017/01/22 05:51 編集
2017/01/22 06:16
2017/01/22 06:44
2017/01/22 15:33 編集
2017/01/23 02:43
2017/01/23 14:57
2017/01/24 10:00 編集
2017/01/24 12:52 編集
2017/01/25 02:00
2017/01/27 01:27 編集
2017/01/27 02:02