Switch case and generics checking
You can use the TypeCode enum for switch:
switch (Type.GetTypeCode(typeof(T)))
{
case TypeCode.Int32:
...
break;
case TypeCode.Decimal:
...
break;
}
Since C# 7.0 you can use pattern matching:
switch (obj)
{
case int i:
...
break;
case decimal d:
...
break;
case UserDefinedType u:
...
break;
}
Beginning with C# 8.0 you can use switch expressions:
string result = obj switch {
int i => $"Integer {i}",
decimal d => $"Decimal {d}",
UserDefinedType u => "User defined {u}",
_ => "unexpected type"
};
Generic type in a switch statement
*A[any]
does not match *A[int]
because any
is a static type, not a wildcard. Therefore instantiating a generic struct with different types yields different types.
In order to correctly match a generic struct in a type switch, you must instantiate it with a type parameter:
func Handle[T any](s interface{}) {
switch x := any(s).(type) {
case *A[T]:
x.DoA()
case *B[T]:
x.DoB()
default:
panic("no match")
}
}
Though in absence of other function arguments to infer T
, you will have to call Handle
with explicit instantiation. T
won't be inferred from the struct alone.
func main() {
i := &A[int]{}
Handle[int](i) // expected to print "do A"
}
Playground: https://go.dev/play/p/2e5E9LSWPmk
However when Handle
is actually a method, as in your database code, this has the drawback of choosing the type parameter when instantiating the receiver.
In order to improve the code here you can make Handle
a top-level function:
func Handle[T any](ctx context.Context, cmd CMD) error {
switch t := cmd.(type) {
case *TransactionalCommand[T]:
return handleTransactionalCommand(ctx, t)
default:
fmt.Printf("%T\n", cmd)
return ErrInvalidCommand
}
}
Then you have the problem of how to supply the argument db T
to the command function. For this, you might:
simply pass an additional
*db
argument toHandle
andhandleTransactionalCommand
, which also helps with type parameter inference. Call asHandle(ctx, &db{}, tFn)
. Playground: https://go.dev/play/p/6WESb86KN5Dpass an instance of
CommandManager
(like solution above but*db
is wrapped). Much more verbose, as it requires explicit instantiation everywhere. Playground: https://go.dev/play/p/SpXczsUM5aWuse a parametrized interface instead (like below). So you don't even have to type-switch. Playground: https://go.dev/play/p/EgULEIL6AV5
type CMD[T any] interface {
Exec(ctx context.Context, db T) error
}
Switching on type with a generic return type
If I understand your intention correctly - you can do it like this:
// no need to pass instance of T - why?
public Mock<DbSet<T>> Mocked<T>() where T : class
{
if (typeof(T) == typeof(Workflow)) {
// first cast to object, then to return type to avoid compile error
// compiler does not know mockedWorkFlows is Mock<DbSet<T>>, but you
// know it already, because you checked type 'T'
return (Mock<DbSet<T>>) (object) mockedWorkFlows; //cannot Workflow to T
}
// etc
return null;
}
Whether it is good idea or not is a different story.
Switching on a generic type?
You need the is
pattern:
func doSomething<T>(type: T.Type) {
switch type {
case is String.Type:
print("It's a String")
case is Int.Type:
print("It's an Int")
default:
print("Wot?")
}
}
Note that the break
statements are usually not needed, there is no
"default fallthrough" in Swift cases.
How to use Switch...Case in generic type parameter in C#?
If you need to know what the type of T
is, you probably aren't using generics properly. Ask yourself: what happens if someone uses a T
that you haven't accounted for?
It seems like what you need is to have a base class Response
and then derive the other classes from it, then you can create a factory method which produces the appropriate instances of the derived classes depending on some logic.
Related Topics
Best Practice for Swift Methods That Can Return or Error
Swift - Avaudioplayer, Sound Doesn't Play Correctly
How to Make Physics Bodies Stick to Nodes Anchor Points
Make Int Round Off to Nearest Value
Convert Generic Free Function into Array Extension
Is There a Writetofile Equivalent for Swift 3's 'Data' Type
Dynamically Change Text of Realitykit Entity
When to Use [Self] VS [Weak Self] in Swift Blocks
Method' Is Ambiguous for Type Lookup in This Context, Error in Alamofire
How to Check the Network Speed Using Swift
How to Use List Type with Codable? (Realmswift)
Extending Collection with a Recursive Property/Method That Depends on the Element Type
How to Write a Function That Will Unwrap a Generic Property in Swift Assuming It Is an Optional Type
How to Track More Than 4 Images at a Time with Arkit
Obj-C Cocoapods + Swift Framework