Is there a name for this pattern? (C# compile-time type-safety with “params” args of different types)

六月ゝ 毕业季﹏ 提交于 2019-12-03 05:48:04
Kit

There doesn't seem to be a named pattern on the Interwebs, but based on Ryan's comment to your question, I vote the name of the pattern should be Variadic Typesafety.

Generally, I would use it very sparingly, but I'm not judging the pattern as good or bad. Many of the commenters have made good points pro and con, which we see for other patterns such as Factory, Service Locator, Dependency Injection, MVVM, etc. It's all about context. So here's a stab at that...

Context

A variable set of disparate objects must be processed.

Use When

  1. Your method can accept a variable number of arguments of disparate types that don't have a common base type.
  2. Your method is widely used (i.e. in many places in code and/or by a great number of users of your framework. The point being that the type-safety provides enough of a benefit to warrant its use.
  3. The arguments can be passed in any order, yet the set of disparate types is finite and the only set acceptable to the method.
  4. Expressiveness is your design goal and you don't want to put the onus on the user to create wrappers or adapters (see Alternatives).

Implementation

You already provided that.

Examples

  • LINQ to XML (e.g. new XElement(...))
  • Other builders such as those that build SQL parameters.
  • Processor facades (e.g. those that could accept different types of delegates or command objects from different frameworks) to execute the commands without the need to create explicit command adapters.

Alternatives

  • Adapter. Accept a variable number of arguments of some adapter type (e.g. Adapter<T> or subclasses of a non-generic Adapter) that the method can work with to produce the desired results. This widens the set your method can use (the types are no-longer finite), but nothing is lost if the adapter does the right thing to enable the processing to still work. The disadvantage is the user has the additional burden of specifying existing and/or creating new adapters, which perhaps detracts from the intent (i.e. adds "ceremony", and weakens "essence").
  • Remove Type Safety. This entails accepting a very base type (e.g. Object) and placing runtime checks. Burden on what to know to pass is passed to the user, but the code is still expressive. Errors don't reveal themselves until runtime.
  • Composite. Pass a single object that is a composite of others. This requires a pre-method-call build up, but devolves back to using one of the above patterns for the items in the composite's collection.
  • Fluent API. Replace the single call with a series of specific calls, one for each type of acceptable argument. A canonical example is StringBuilder.

It is called an anti-pattern more commonly known as Poltergeist.

Update:

If the types of args are always constant and the order does not matter, then create overloads that each take collections (IEnumerable<T>) changing T in each method for the type you need to operate on. This will reduce your code complexity by:

  1. Removing the MyArg class
  2. eliminating the need for type casting in your MyMethod
  3. will add an additional compile time type safety in that if you try to call the method with a list of args that you can't handle, you will get a compiler exception.

This looks like a subset of the Composite Pattern. Quoting from Wikipedia:

The composite pattern describes that a group of objects are to be treated in the same way as a single instance of an object.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!