enum method returning a dynamic type
I think the core of the problem here is that Swift has strict typing. That means types must be known at compile time. This, obviously, is legal:
let s : Any = "howdy"
if let ss = s as? String {
print(ss)
}
But this is not legal:
let s : Any = "howdy"
let someType = String.self
if let ss = s as? someType { // *
print(ss)
}
someType
must be a type; it cannot be a variable hiding a type inside itself. But that is precisely what, in effect, you are asking to do.
Return specific type in generic method depending on enum value without Reflection or dynamic during runtime
Think about how this method would be used:
ItemType itemType = ...;
var x = listView.GetItems(itemType);
The value of itemType
could be A
, or it could be B
. So what should the type of x
be? It's either IList<A>
, or IList<B>
, and the only way to express that is to use a type that both IList<A>
and IList<B>
inherit from, which takes us back to IList
. If you don't know the type that you want at compile time, then there is not much point trying to change the return type to something more specific, because you will not be able to access it as the more specific type without reflection.
If you do know the type that you want at compile time, then provide overloads of the method that return the desired type:
public IList<A> GetAItems() { ... }
public IList<B> GetBItems() { ... }
Edit
If you really want to use a generic method, you could do something like this:
public IList<T> GetItems<T>()
{
return itemsSource.Cast<T>().ToList();
}
But I don't see the point in making a method for this, rather than putting that code directly where you need the specific type.
Edit 2
Having seen your use case, I really would recommend you make the CustomListView
class generic. I know you say the library prevents that, but there are ways to work around this. You've made an ItemType
enum, you could instead make a subclass of CustomListView<T>
for each item type:
public class CustomListView<T> : ListView
{
public IList<T> GetItems() => itemsSources.Cast<T>().ToList();
}
public class CustomListViewOfA : CustomListView<A> { }
public class CustomListViewOfB : CustomListView<B> { }
public class UiForClassA
{
public void Foo()
{
var customListView = new CustomListViewOfA();
var itemsOfCustomListView = customListView.GetItems(); //No cast needed
}
}
Using dynamic enum as type in a parameter of a method
You'll either have to pass in an object, or create your method dynamically as well.
Might I ask why you can't just use an int
for this? Seems like you're going to have to dynamically create a lot of code just to be able to pass it around as an enum.
How to type-hint a method that retrieves dynamic enum value?
As you don't want to check-type for any Enum
, I suggest to introduce a base type (say GrammaticalEnum
) to mark all your Enum
s and to group them in an own module:
# module grammar_enums
import sys
import inspect
from enum import Enum
class GrammaticalEnum(Enum):
"""use as a base to mark all grammatical enums"""
pass
class WordType(GrammaticalEnum):
ADJ = "Adjective"
ADV = "Adverb"
class Number(GrammaticalEnum):
S = "Singular"
P = "Plural"
# keep this statement at the end, as all enums must be known first
grammatical_enums = dict(
m for m in inspect.getmembers(sys.modules[__name__], inspect.isclass)
if issubclass(m[1], GrammaticalEnum))
# you might prefer the shorter alternative:
# grammatical_enums = {k: v for (k, v) in globals().items()
# if inspect.isclass(v) and issubclass(v, GrammaticalEnum)}
Regarding typing, yakir0 already suggested the right types,
but with the common base you can narrow them.
If you like, you even could get rid of your functions at all:
from grammar_enums import grammatical_enums as g_enums
from grammar_enums import GrammaticalEnum
# just use g_enums instead of get_enum_value like this
WordType_ADJ: GrammaticalEnum = g_enums['WordType']['ADJ']
# ...or use your old functions:
# as your grammatical enums are collected in a dict now,
# you don't need this function any more:
def get_enum_type(name: str) -> Type[GrammaticalEnum]:
return g_enums[name]
def get_enum_value(enum_name: str, value_name: str) -> GrammaticalEnum:
# return get_enum_type(enum_name)[value_name]
return g_enums[enum_name][value_name]
Creating Enum variable from a dynamic type that I know is an Enum?
Enum.ToObject(Type,object)
solved this.
For example after I confirmed that type
is a System.Enum
then I can do (System.Enum)Enum.ToObject(type,0)
.
It's confusing because despite the name Enum.ToObject
, this method convert object to enum not enum to object. But maybe the name is referring to returned type of this method which is object
.
How to pass a generic enum to a method and set it to a dynamic object inside the method
Using reflection
public void MyMethod(string otherParam, object someObject)
{
var prop = someObject.GetType().GetProperty("cigarettes");
var enumType = prop.PropertyType;
prop.SetValue(someObject, Enum.Parse(enumType, "yes"), null);
}
This gets the information about the "cigarettes" property using reflection, including the enum type. Enum.Parse(enumType, string)
or Enum.ToObject(enumType, intValue)
can then be used to construct a value of this type. SetValue
writes the constructed value to the property.
Using generics
An alternative - if the value is fixed - would be to make the method generic and pass the enum value to the method:
public void MyMethod<T>(string otherParam, dynamic someObject, T value)
{
someObject.cigarettes = value;
}
Call: MyMethod("x", obj, yesnounspecified.yes);
Return Enum of null dynamically using the Type
Returning null
from the ReadJson
method should be all you need to do. Nullable<T>
is a value type (even though you can test for and assign null
to it). When it gets boxed into a referenced type (object
for example), then it does one of two things:
- If the value represented by
Nullable<T>
is NOTnull
, then theValue
is boxed just like any other value type would be. - If
Nullable<T>
is reprsenting anull
value, then the result is actuallynull
.
The reverse happens when you unbox (going from a reference type to Nullable<T>
); if the reference type is null
, then a new instance of Nullable<T>
is created and is set such that it does not have a value, but if the reference type does hold a value, then a new Nullable<T>
instance is created and the value within the reference type is set to be the current value of the Nullable<T>
.
The reason calling GetValueOrDefault
doesn't work is because, for Nullable<T>
the return type of that method is T
, which must be a value type, so it cannot be null
.
Enum with dynamic method parameters
You can't really do anything "dynamic" with the constructor: SUCCESS
and ENUM
are static references that will each be initialized to point to a new MyEnum instance when the class is loaded. The constructor will be called once each, and then never again during the lifetime of the program.
I thought of achieving this by passing params in the getMessage method instead... Is there any better option than doing this?
No better way that I can think of.
Related Topics
How to Make Text Typed in Textfield Undeletable
How to Perform Conditional Segue
Dispatchworkitem Not Notifying Main Thread
Cicolorcontrols & Uislider W/ Swift 4
How to Conditionally Define a Podspec Property Depending on Static or Dynamic Usage
Xcode Swift 3: Timer and Segue View Controller Error
Aws Cognito/Getting User Information from the Sub
Toggle Selectedrange Attributes in Uitextview
Enum Method Returning a Dynamic Type
Why Aren't My Custom Classes Appearing in the Dropdown in Interface Builder
Implementing a 'Report' Feature for Inappropriate Content Swift Firebase
Realm Data Doesn't Show Up on a Physical Device
Problem Creating and Writing a Subdirectory in Swift 5
How to Handle Async Requests in Swift
Advancedby' in Swift Is Unavailable
Randomize Two Arrays the Same Way Swift
Swiftui - Mapkit - Binding Mapkit and Show View on Annotation Callout Buttons