1 class Program 2 { 3 delegate T Func<out T>(); 4 delegate void Action<in T>(T obj); 5 static void Main(string[] args) 6 { 7 Func<Square> squareFactory = () => new Square(new Point(5, 5), 10); 8 Func<IShape> shapeFactory = squareFactory; 9 10 Action<IShape> shapePrinter = shape => Console.WriteLine(shape.Area); 11 Action<Square> squarePrinter = shapePrinter; 12 13 shapePrinter(shapeFactory()); 14 squarePrinter(squareFactory()); 15 } 16 }
我们的方形工厂总是生产位置相同且边长都为10的正方形。
协变性允许我们将方形工厂视为更一般的形状工厂 ,这没有什么奇怪的。然后我们创建了一个通用的行为,打印任意形状的面积。这次我们使用逆变转换,让行为可用于任意方形 。
最后,我们将方形工厂的结果提供给方形行为(action),将形状工厂的结果提供给形状行为。结果都是预期的100。
1 public class SampleData 2 { 3 static List<Defect> defects; 4 static List<User> users; 5 static List<Project> projects; 6 static List<NotificationSubscription> subscriptions; 7 8 public static readonly DateTime Start = May(1); 9 public static readonly DateTime End = May(31); 10 11 public static IEnumerable<Defect> AllDefects 12 { 13 get { return defects; } 14 } 15 16 public static IEnumerable<User> AllUsers 17 { 18 get { return users; } 19 } 20 21 public static IEnumerable<Project> AllProjects 22 { 23 get { return projects; } 24 } 25 26 public static IEnumerable<NotificationSubscription> AllSubscriptions 27 { 28 get { return subscriptions; } 29 } 30 31 public static class Projects 32 { 33 public static readonly Project SkeetyMediaPlayer = new Project { Name = "Skeety Media Player" }; 34 public static readonly Project SkeetyTalk = new Project { Name = "Skeety Talk" }; 35 public static readonly Project SkeetyOffice = new Project { Name = "Skeety Office" }; 36 } 37 38 public static class Users 39 { 40 public static readonly User TesterTim = new User("Tim Trotter", UserType.Tester); 41 public static readonly User TesterTara = new User("Tara Tutu", UserType.Tester); 42 public static readonly User DeveloperDeborah = new User("Deborah Denton", UserType.Developer); 43 public static readonly User DeveloperDarren = new User("Darren Dahlia", UserType.Developer); 44 public static readonly User ManagerMary = new User("Mary Malcop", UserType.Manager); 45 public static readonly User CustomerColin = new User("Colin Carton", UserType.Customer); 46 } 47 48 static SampleData() 49 { 50 projects = new List<Project> 51 { 52 Projects.SkeetyMediaPlayer, 53 Projects.SkeetyTalk, 54 Projects.SkeetyOffice 55 }; 56 57 users = new List<User> 58 { 59 Users.TesterTim, 60 Users.TesterTara, 61 Users.DeveloperDeborah, 62 Users.DeveloperDarren, 63 Users.ManagerMary, 64 Users.CustomerColin 65 }; 66 67 subscriptions = new List<NotificationSubscription> 68 { 69 new NotificationSubscription { Project=Projects.SkeetyMediaPlayer, EmailAddress="media-bugs@skeetysoft.com" }, 70 new NotificationSubscription { Project=Projects.SkeetyTalk, EmailAddress="talk-bugs@skeetysoft.com" }, 71 new NotificationSubscription { Project=Projects.SkeetyOffice, EmailAddress="office-bugs@skeetysoft.com" }, 72 new NotificationSubscription { Project=Projects.SkeetyMediaPlayer, EmailAddress="theboss@skeetysoft.com"} 73 }; 74 75 defects = new List<Defect> 76 { 77 new Defect 78 { 79 Project = Projects.SkeetyMediaPlayer, 80 Created = May(1), 81 CreatedBy = Users.TesterTim, 82 Summary = "MP3 files crash system", 83 Severity = Severity.Showstopper, 84 AssignedTo = Users.DeveloperDarren, 85 Status = Status.Accepted, 86 LastModified = May(23) 87 }, 88 89 new Defect 90 { 91 Project = Projects.SkeetyMediaPlayer, 92 Created = May(3), 93 CreatedBy = Users.DeveloperDeborah, 94 Summary = "Text is too big", 95 Severity = Severity.Trivial, 96 AssignedTo = null, 97 Status = Status.Closed, 98 LastModified = May(9) 99 }, 100 101 new Defect 102 { 103 Project = Projects.SkeetyTalk, 104 Created = May(3), 105 CreatedBy = Users.CustomerColin, 106 Summary = "Sky is wrong shade of blue", 107 Severity = Severity.Minor, 108 AssignedTo = Users.TesterTara, 109 Status = Status.Fixed, 110 LastModified = May(19) 111 }, 112 113 new Defect 114 { 115 Project = Projects.SkeetyMediaPlayer, 116 Created = May(4), 117 CreatedBy = Users.DeveloperDarren, 118 Summary = "Can't play files more than 200 bytes long", 119 Severity = Severity.Major, 120 AssignedTo = Users.DeveloperDarren, 121 Status = Status.Reopened, 122 LastModified = May(23) 123 }, 124 125 new Defect 126 { 127 Project = Projects.SkeetyMediaPlayer, 128 Created = May(6), 129 CreatedBy = Users.TesterTim, 130 Summary = "Installation is slow", 131 Severity = Severity.Trivial, 132 AssignedTo = Users.TesterTim, 133 Status = Status.Fixed, 134 LastModified = May(15) 135 }, 136 137 new Defect 138 { 139 Project = Projects.SkeetyMediaPlayer, 140 Created = May(7), 141 CreatedBy = Users.ManagerMary, 142 Summary = "DivX is choppy on Pentium 100", 143 Severity = Severity.Major, 144 AssignedTo = Users.DeveloperDarren, 145 Status = Status.Accepted, 146 LastModified = May(29) 147 }, 148 149 new Defect 150 { 151 Project = Projects.SkeetyTalk, 152 Created = May(8), 153 CreatedBy = Users.DeveloperDeborah, 154 Summary = "Client acts as virus", 155 Severity = Severity.Showstopper, 156 AssignedTo = null, 157 Status = Status.Closed, 158 LastModified = May(10) 159 }, 160 161 new Defect 162 { 163 Project = Projects.SkeetyMediaPlayer, 164 Created = May(8), 165 CreatedBy = Users.DeveloperDarren, 166 Summary = "Subtitles only work in Welsh", 167 Severity = Severity.Major, 168 AssignedTo = Users.TesterTim, 169 Status = Status.Fixed, 170 LastModified = May(23) 171 }, 172 173 new Defect 174 { 175 Project = Projects.SkeetyTalk, 176 Created = May(9), 177 CreatedBy = Users.CustomerColin, 178 Summary = "Voice recognition is confused by background noise", 179 Severity = Severity.Minor, 180 AssignedTo = null, 181 Status = Status.Closed, 182 LastModified = May(15) 183 }, 184 185 new Defect 186 { 187 Project = Projects.SkeetyTalk, 188 Created = May(9), 189 CreatedBy = Users.TesterTim, 190 Summary = "User interface should be more caramelly", 191 Severity = Severity.Trivial, 192 AssignedTo = Users.DeveloperDarren, 193 Status = Status.Created, 194 LastModified = May(9) 195 }, 196 197 new Defect 198 { 199 Project = Projects.SkeetyMediaPlayer, 200 Created = May(10), 201 CreatedBy = Users.ManagerMary, 202 Summary = "Burning a CD makes the printer catch fire", 203 Severity = Severity.Showstopper, 204 AssignedTo = null, 205 Status = Status.Closed, 206 LastModified = May(29) 207 }, 208 209 new Defect 210 { 211 Project = Projects.SkeetyTalk, 212 Created = May(10), 213 CreatedBy = Users.TesterTara, 214 Summary = "Peer to peer pairing passes parameters poorly", 215 Severity = Severity.Minor, 216 AssignedTo = Users.DeveloperDarren, 217 Status = Status.Accepted, 218 LastModified = May(12) 219 }, 220 221 new Defect 222 { 223 Project = Projects.SkeetyTalk, 224 Created = May(11), 225 CreatedBy = Users.DeveloperDarren, 226 Summary = "Delay when sending message", 227 Severity = Severity.Minor, 228 AssignedTo = Users.TesterTara, 229 Status = Status.Fixed, 230 LastModified = May(20) 231 }, 232 233 new Defect 234 { 235 Project = Projects.SkeetyMediaPlayer, 236 Created = May(11), 237 CreatedBy = Users.ManagerMary, 238 Summary = "Volume control needs to go to 11", 239 Severity = Severity.Minor, 240 AssignedTo = Users.DeveloperDarren, 241 Status = Status.Created, 242 LastModified = May(11) 243 }, 244 245 new Defect 246 { 247 Project = Projects.SkeetyMediaPlayer, 248 Created = May(11), 249 CreatedBy = Users.CustomerColin, 250 Summary = "Splash screen fades too quickly", 251 Severity = Severity.Minor, 252 AssignedTo = Users.TesterTara, 253 Status = Status.Fixed, 254 LastModified = May(15) 255 }, 256 257 new Defect 258 { 259 Project = Projects.SkeetyTalk, 260 Created = May(12), 261 CreatedBy = Users.DeveloperDeborah, 262 Summary = "Text box doesn't keep up with fast typing", 263 Severity = Severity.Major, 264 AssignedTo = Users.DeveloperDeborah, 265 Status = Status.Accepted, 266 LastModified = May(12) 267 }, 268 269 new Defect 270 { 271 Project = Projects.SkeetyTalk, 272 Created = May(12), 273 CreatedBy = Users.DeveloperDarren, 274 Summary = "Password displayed in plain text", 275 Severity = Severity.Showstopper, 276 AssignedTo = null, 277 Status = Status.Closed, 278 LastModified = May(13) 279 }, 280 281 new Defect 282 { 283 Project = Projects.SkeetyMediaPlayer, 284 Created = May(12), 285 CreatedBy = Users.TesterTim, 286 Summary = "Play button points the wrong way", 287 Severity = Severity.Major, 288 AssignedTo = Users.TesterTim, 289 Status = Status.Fixed, 290 LastModified = May(17) 291 }, 292 293 new Defect 294 { 295 Project = Projects.SkeetyMediaPlayer, 296 Created = May(13), 297 CreatedBy = Users.CustomerColin, 298 Summary = "Wizard needed for CD burning", 299 Severity = Severity.Minor, 300 AssignedTo = Users.CustomerColin, 301 Status = Status.Fixed, 302 LastModified = May(20) 303 }, 304 305 new Defect 306 { 307 Project = Projects.SkeetyMediaPlayer, 308 Created = May(13), 309 CreatedBy = Users.ManagerMary, 310 Summary = "Subtitles don't display during fast forward", 311 Severity = Severity.Trivial, 312 AssignedTo = Users.DeveloperDarren, 313 Status = Status.Accepted, 314 LastModified = May(14) 315 }, 316 317 new Defect 318 { 319 Project = Projects.SkeetyMediaPlayer, 320 Created = May(13), 321 CreatedBy = Users.DeveloperDarren, 322 Summary = "Memory leak when watching Memento", 323 Severity = Severity.Trivial, 324 AssignedTo = Users.DeveloperDeborah, 325 Status = Status.Created, 326 LastModified = May(13) 327 }, 328 329 new Defect 330 { 331 Project = Projects.SkeetyTalk, 332 Created = May(13), 333 CreatedBy = Users.DeveloperDeborah, 334 Summary = "Profile screen shows login count of -1", 335 Severity = Severity.Major, 336 AssignedTo = Users.DeveloperDeborah, 337 Status = Status.Accepted, 338 LastModified = May(20) 339 }, 340 341 new Defect 342 { 343 Project = Projects.SkeetyTalk, 344 Created = May(13), 345 CreatedBy = Users.TesterTim, 346 Summary = "Server crashes under heavy load (3 users)", 347 Severity = Severity.Major, 348 AssignedTo = Users.DeveloperDeborah, 349 Status = Status.Accepted, 350 LastModified = May(17) 351 }, 352 353 new Defect 354 { 355 Project = Projects.SkeetyMediaPlayer, 356 Created = May(15), 357 CreatedBy = Users.TesterTara, 358 Summary = "Unable to connect to any media server", 359 Severity = Severity.Showstopper, 360 AssignedTo = Users.DeveloperDarren, 361 Status = Status.Reopened, 362 LastModified = May(18) 363 }, 364 365 new Defect 366 { 367 Project = Projects.SkeetyMediaPlayer, 368 Created = May(15), 369 CreatedBy = Users.DeveloperDeborah, 370 Summary = "UI turns black and white when playing old films", 371 Severity = Severity.Minor, 372 AssignedTo = Users.TesterTara, 373 Status = Status.Fixed, 374 LastModified = May(25) 375 }, 376 377 new Defect 378 { 379 Project = Projects.SkeetyTalk, 380 Created = May(16), 381 CreatedBy = Users.ManagerMary, 382 Summary = "Password reset changes passwords for all users", 383 Severity = Severity.Showstopper, 384 AssignedTo = null, 385 Status = Status.Closed, 386 LastModified = May(18) 387 }, 388 389 new Defect 390 { 391 Project = Projects.SkeetyMediaPlayer, 392 Created = May(17), 393 CreatedBy = Users.TesterTim, 394 Summary = "Modern music sounds rubbish", 395 Severity = Severity.Trivial, 396 AssignedTo = Users.DeveloperDarren, 397 Status = Status.Created, 398 LastModified = May(17) 399 }, 400 401 new Defect 402 { 403 Project = Projects.SkeetyTalk, 404 Created = May(18), 405 CreatedBy = Users.TesterTim, 406 Summary = "Webcam makes me look bald", 407 Severity = Severity.Showstopper, 408 AssignedTo = Users.TesterTim, 409 Status = Status.Fixed, 410 LastModified = May(27) 411 }, 412 413 new Defect 414 { 415 Project = Projects.SkeetyTalk, 416 Created = May(18), 417 CreatedBy = Users.CustomerColin, 418 Summary = "Sound is distorted when speakers are underwater", 419 Severity = Severity.Major, 420 AssignedTo = Users.DeveloperDarren, 421 Status = Status.Created, 422 LastModified = May(18) 423 }, 424 425 new Defect 426 { 427 Project = Projects.SkeetyTalk, 428 Created = May(19), 429 CreatedBy = Users.DeveloperDarren, 430 Summary = "Japanese characters don't display properly", 431 Severity = Severity.Major, 432 AssignedTo = Users.DeveloperDeborah, 433 Status = Status.Accepted, 434 LastModified = May(23) 435 }, 436 437 new Defect 438 { 439 Project = Projects.SkeetyMediaPlayer, 440 Created = May(20), 441 CreatedBy = Users.TesterTara, 442 Summary = "Video takes 100% of CPU", 443 Severity = Severity.Major, 444 AssignedTo = Users.DeveloperDeborah, 445 Status = Status.Accepted, 446 LastModified = May(22) 447 }, 448 449 new Defect 450 { 451 Project = Projects.SkeetyMediaPlayer, 452 Created = May(22), 453 CreatedBy = Users.TesterTim, 454 Summary = "DVD Easter eggs unavailable", 455 Severity = Severity.Trivial, 456 AssignedTo = Users.DeveloperDarren, 457 Status = Status.Created, 458 LastModified = May(22) 459 }, 460 461 new Defect 462 { 463 Project = Projects.SkeetyTalk, 464 Created = May(23), 465 CreatedBy = Users.ManagerMary, 466 Summary = "Transparency is high for menus to be readable", 467 Severity = Severity.Minor, 468 AssignedTo = Users.DeveloperDeborah, 469 Status = Status.Accepted, 470 LastModified = May(25) 471 }, 472 473 new Defect 474 { 475 Project = Projects.SkeetyMediaPlayer, 476 Created = May(24), 477 CreatedBy = Users.CustomerColin, 478 Summary = "About box is missing version number", 479 Severity = Severity.Minor, 480 AssignedTo = Users.CustomerColin, 481 Status = Status.Fixed, 482 LastModified = May(29) 483 }, 484 485 new Defect 486 { 487 Project = Projects.SkeetyTalk, 488 Created = May(25), 489 CreatedBy = Users.TesterTim, 490 Summary = "Logs record confidential conversations", 491 Severity = Severity.Major, 492 AssignedTo = Users.DeveloperDarren, 493 Status = Status.Reopened, 494 LastModified = May(30) 495 }, 496 497 new Defect 498 { 499 Project = Projects.SkeetyTalk, 500 Created = May(27), 501 CreatedBy = Users.DeveloperDeborah, 502 Summary = "Profanity filter is too aggressive", 503 Severity = Severity.Minor, 504 AssignedTo = Users.TesterTara, 505 Status = Status.Fixed, 506 LastModified = May(29) 507 }, 508 509 new Defect 510 { 511 Project = Projects.SkeetyMediaPlayer, 512 Created = May(27), 513 CreatedBy = Users.TesterTara, 514 Summary = "Full screen mode fails on dual monitors", 515 Severity = Severity.Minor, 516 AssignedTo = Users.DeveloperDeborah, 517 Status = Status.Created, 518 LastModified = May(27) 519 }, 520 521 new Defect 522 { 523 Project = Projects.SkeetyMediaPlayer, 524 Created = May(28), 525 CreatedBy = Users.CustomerColin, 526 Summary = "Visualization hypnotises pets", 527 Severity = Severity.Minor, 528 AssignedTo = Users.DeveloperDeborah, 529 Status = Status.Accepted, 530 LastModified = May(29) 531 }, 532 533 new Defect 534 { 535 Project = Projects.SkeetyTalk, 536 Created = May(29), 537 CreatedBy = Users.ManagerMary, 538 Summary = "Resizing while typing loses input", 539 Severity = Severity.Trivial, 540 AssignedTo = Users.DeveloperDarren, 541 Status = Status.Created, 542 LastModified = May(29) 543 }, 544 545 new Defect 546 { 547 Project = Projects.SkeetyMediaPlayer, 548 Created = May(30), 549 CreatedBy = Users.TesterTim, 550 Summary = "Network is saturated when playing WAV file", 551 Severity = Severity.Minor, 552 AssignedTo = Users.TesterTim, 553 Status = Status.Fixed, 554 LastModified = May(31) 555 }, 556 557 new Defect 558 { 559 Project = Projects.SkeetyMediaPlayer, 560 Created = May(31), 561 CreatedBy = Users.TesterTara, 562 Summary = "Media library tells user to keep the noise down", 563 Severity = Severity.Major, 564 AssignedTo = Users.DeveloperDarren, 565 Status = Status.Created, 566 LastModified = May(31) 567 } 568 }; 569 } 570 571 public static DateTime May(int day) 572 { 573 return new DateTime(2013, 5, day); 574 } 575 576 } 577 public enum UserType : byte 578 { 579 Customer, 580 Developer, 581 Tester, 582 Manager, 583 } 584 public class Defect 585 { 586 public Project Project { get; set; } 587 /// <summary> 588 /// Which user is this defect currently assigned to? Should not be null until the status is Closed. 589 /// </summary> 590 public User AssignedTo { get; set; } 591 public string Summary { get; set; } 592 public Severity Severity { get; set; } 593 public Status Status { get; set; } 594 public DateTime Created { get; set; } 595 public DateTime LastModified { get; set; } 596 public User CreatedBy { get; set; } 597 public int ID { get; private set; } 598 599 public Defect() 600 { 601 ID = StaticCounter.Next(); 602 } 603 604 public override string ToString() 605 { 606 return string.Format("{0,2}: {1} ({2:d}-{3:d}, {4}/{5}, {6} -> {7})", 607 ID, Summary, Created, LastModified, Severity, Status, CreatedBy.Name, 608 AssignedTo == null ? "n/a" : AssignedTo.Name); 609 } 610 } 611 public class NotificationSubscription 612 { 613 /// <summary> 614 /// Project for which this subscriber is notified 615 /// </summary> 616 public Project Project { get; set; } 617 618 /// <summary> 619 /// The address to send the notification to 620 /// </summary> 621 public string EmailAddress { get; set; } 622 } 623 public class Project 624 { 625 public string Name { get; set; } 626 627 public override string ToString() 628 { 629 return string.Format("Project: {0}", Name); 630 } 631 } 632 public enum Severity : byte 633 { 634 Trivial, 635 Minor, 636 Major, 637 Showstopper, 638 } 639 public static class StaticCounter 640 { 641 static int next = 1; 642 public static int Next() 643 { 644 return next++; 645 } 646 } 647 public enum Status : byte 648 { 649 /// <summary> 650 /// Defect has been opened, but not verified as reproducible or an issue. 651 /// </summary> 652 Created, 653 /// <summary> 654 /// Defect has been verified as an issue requiring work. 655 /// </summary> 656 Accepted, 657 /// <summary> 658 /// Defect has been fixed in code, but not verified other than through developer testing. 659 /// </summary> 660 Fixed, 661 /// <summary> 662 /// Defect was fixed, but has now been reopened due to failing verification. 663 /// </summary> 664 Reopened, 665 /// <summary> 666 /// Defect has been fixed and tested; the fix is satisfactory. 667 /// </summary> 668 Closed, 669 } 670 public class User 671 { 672 public string Name { get; set; } 673 public UserType UserType { get; set; } 674 675 public User(string name, UserType userType) 676 { 677 Name = name; 678 UserType = userType; 679 } 680 681 public override string ToString() 682 { 683 return string.Format("User: {0} ({1})", Name, UserType); 684 } 685 } 686 static class Extensions 687 { 688 public static Dummy<T> Where<T>(this Dummy<T> dummy, Func<T, bool> predicate) 689 { 690 Console.WriteLine("Where called"); 691 return dummy; 692 } 693 } 694 class Dummy<T> 695 { 696 public Dummy<U> Select<U>(Func<T, U> selector) 697 { 698 Console.WriteLine("Select called"); 699 return new Dummy<U>(); 700 } 701 } 702 public class DateTimeRange : IEnumerable<DateTime> 703 { 704 private readonly DateTime start; 705 private readonly DateTime end; 706 707 public DateTimeRange(DateTime start, DateTime end) 708 { 709 this.start = start; 710 this.end = end; 711 } 712 713 public IEnumerator<DateTime> GetEnumerator() 714 { 715 for (DateTime current = start; current <= end; current = current.AddDays(1)) 716 { 717 yield return current; 718 } 719 } 720 721 IEnumerator IEnumerable.GetEnumerator() 722 { 723 return GetEnumerator(); 724 } 725 }