Enum Method Returning a Dynamic Type

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 Enums 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:

  1. If the value represented by Nullable<T> is NOT null, then the Value is boxed just like any other value type would be.
  2. If Nullable<T> is reprsenting a null value, then the result is actually null.

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



Leave a reply



Submit