将对象转换为泛型类型实例

时间:2020-10-22 14:40:11

标签: c# .net generics casting

我有一个这样定义的类Option<T>

class Option<T>
{
     T Value { get; set; }
     bool HasValue { get; }
}

在我的代码的某个时刻,此类的实例通过回调object(在value内部传递)发送给我

private void Callback(object value)
{
}

我想将值转换为Option<T>,但是在编译时我不知道类型T。 如何“上载”实例以进行检查,例如Value属性?

2 个答案:

答案 0 :(得分:1)

您在评论中告诉我们的唯一一件事就是您要访问HasValue。那很容易-创建一个界面

public interface IOption
{
    bool HasValue { get; }
}

class Option<T> : IOption
{
     T Value { get; set; }
     bool HasValue { get; }
}

并将收到的object投射到IOption。如果您还需要提取值,则需要带有covariant type parameter

的附加接口
public interface IOption<out T> : IOption
{
    T Value { get; }
}

class Option<T> : IOption<T>
{
    T Value { get; set; }
    bool HasValue { get; }
}

然后您就可以将object强制转换为IOption<object>,并且对任何T都可以成功,从而可以将Value检索为object 。不过,您将无法进行设置。

答案 1 :(得分:0)

如果您知道所有可能性,则可以使用模式匹配:

        public static void Main(string[] args) 
        {
            object someOption = new Option<DateTime>() { Value = DateTime.Now};
            
            switch (someOption)
            {
                case Option<DateTime> dt: 
                    Console.WriteLine($"Date: {dt.Value}");
                    break;
                case Option<string> str:
                    Console.WriteLine($"String: {str}");
                    break;
            }
        }

否则,这可能是您的解决方案。在需要将对象传递给其他泛型方法或在泛型类型中使用它时,有时会使用类似的概念。

        interface IOptionHandler
        {
            void Handle(object option);
        }
        static class OptionHandler
        {
            public static IOptionHandler Create(Type targetType)
            {
                // normally you would check if it really is an Option<T> 
                // by providing some non-generic interface like IOption
                // we skip this part

                var typeParam = targetType.GetGenericArguments()[0];
                var helperType = typeof(Helper<>).MakeGenericType(typeParam);
                return (IOptionHandler) Activator.CreateInstance(helperType);
            }

            class Helper<T> : IOptionHandler
            {
                public void Handle(object option)
                {
                    // in this context you can use all the generic powers again
                    Option<T> myOlOption = (Option<T>) option;

                    List<Option<T>> whatever = new List<Option<T>>();
                    whatever.Add(myOlOption);

                    Console.WriteLine($"{myOlOption.Value.GetType()}: {myOlOption.Value}");
                }
            }
        }

        public static void Main(string[] args) 
        {
            object someOption = new Option<DateTime>() { Value = DateTime.Now};

            var handler = OptionHandler.Create(someOption.GetType());
            handler.Handle(someOption);
        }

我通常会缓存创建的帮助对象,但这完全取决于用例。