如何将对象转换为由Type变量指定的类型

时间:2019-02-18 15:52:46

标签: c# dynamic types casting .net-3.5

我正在寻找一种将object变量转换为具有类型Type的其他变量指定的通用类型参数的类型的方法。

我仅限于.NET 3.5,因此不能使用dynamic :( 这里的主要思想是我可以使用字典:

Dictionary<Type, object> data;

该词典中的数据仅以以下形式添加:

data.Add(T, new DataSub<T>(someValueOfTypeT));

问题是,当我尝试撤消该过程时:

foreach(var dataType in data.Keys) {
  var dataValue = data[dataType];
  ProcessDataValue(dataType, dataValue);
}

现在的问题是我如何设法将对象投射到DataSub?

简化的DataSub.cs

public class DataSub<T>
{
  private T _cache;
  public T Value {
    get { return _cache; }
    set { _cache = value; }
  }
}

它如何在ProcessDataValue中工作:

public void ProcessDataValue(Type dataType, object dataValue)
{
  var data = dataValue as DataSub<dataType>;
  if (data == null) return;
  AddProcessedDataValue(dataType, data.Value.ToString());
}

1 个答案:

答案 0 :(得分:1)

如果您可以对发布的类进行最小的更改,并且如果-如您的示例所示-您将对DataSub.Value进行的操作是ToString < / strong>,也许您可​​以通过

获得所需的结果
    public interface IDataSub {
        bool MatchesType(Type t);

        object GetValue();
    }

    public class DataSub<T> : IDataSub {
        private T _cache;
        public T Value {
            get { return _cache; }
            set { _cache = value; }
        }

        public bool MatchesType(Type t) {
            return typeof(T) == t; // or something similar, in order to handle inheritance
        }

        public object GetValue() {
            return Value;
        }
    }

    public class Client {
        Dictionary<Type, IDataSub> data = new Dictionary<Type, IDataSub>() ;


        public void AddData<T>(T someValueOfTypeT) {
            data.Add(typeof(T), new DataSub<T> { Value = someValueOfTypeT });
        }


        public void UseData() {
            foreach(var dataType in data.Keys) {
                var dataValue = data[dataType];
                ProcessDataValue(dataType, dataValue);
            }
        }

        public void ProcessDataValue(Type dataType, IDataSub dataValue)
        {
            if(dataValue.MatchesType(dataType))
                AddProcessedDataValue(dataType, dataValue.GetValue().ToString());
        }
    }

如果仅以DataSub.Value.ToString的使用为例,并且在现实世界中,您需要使用其DataSub.Value类型访问T < / strong>,您应该对代码进行更广泛的修改。

您如何看待以下方法?这是我喜欢的模式set of responsibility(我写了有关此主题的链接文章)的一种应用,它是GoF的chain of responsibility的一种变体:

    public interface IDataSub {
        object GetValue();
    }

    public class DataSub<T> : IDataSub {
        private T _cache;
        public T Value {
            get { return _cache; }
            set { _cache = value; }
        }

        public object GetValue() {
            return Value;
        }
    }

    public interface IDataHandler {
        bool CanHandle(Type type);

        void Handle(object data);
    }

    public class Client {
        private readonly Dictionary<Type, IDataSub> data = new Dictionary<Type, IDataSub>();
        private readonly IList<IDataHandler> handlers = new List<IDataHandler>();


        public void AddData<T>(T someValueOfTypeT) {
            data.Add(typeof(T), new DataSub<T> { Value = someValueOfTypeT });
        }

        public void RegisterHandler(IDataHandler handler) {
            handlers.Add(handler);
        }


        public void UseData() {
            foreach(var dataType in data.Keys) {
                handlers.FirstOrDefault(h => h.CanHandle(dataType))?.Handle(data[dataType].GetValue());
            }
        }

        // Lambda-free version
//        public void UseData() {
//            foreach(var dataType in data.Keys) {
//                for (int i = 0; i < handlers.Count; i++) {
//                    if (handlers[i].CanHandle(dataType)) {
//                        handlers[i].Handle(data[dataType].GetValue());
//                        break; // I don't like breaks very much...
//                    }
//                }
//            }
//        }
    }

    class StringDataHandler : IDataHandler {
        public bool CanHandle(Type type) {
            // Your logic to check if this handler implements logic applyable to instances of type
            return typeof(string) == type;
        }

        public void Handle(object data) {
            string value = (string) data;
            // Do something with string
        }
    }

    class IntDataHandler : IDataHandler {
        public bool CanHandle(Type type) {
            // Your logic to check if this handler implements logic applyable to instances of type
            return typeof(int) == type;
        }

        public void Handle(object data) {
            int value = (int) data;
            // Do something with int
        }
    }

这种方法允许您将数据存储和数据迭代逻辑与针对不同数据类型的特定数据处理逻辑分离:IDataHandler的实现已知它们可以处理和转换通用{{1}的数据类型}引用所需的类型。如果愿意,可以将object方法合并到CanHandle方法中,删除以前的方法并将Handle更改为

UseData

和处理程序实现

public void UseData() {
    foreach(var dataType in data.Keys) {
        foreach(var handler in handlers) {
            handler.Handle(dataType, data[dataType].GetValue())
        }
    }
}

此变体的类型安全性更高一些,因为在第一个变体中,可以在不事先调用class IntDataHandler : IDataHandler { public void Handle(Type dataType, object data) { if(typeof(int) == type) { int value = (int) data; // Do something with int } } } 的情况下调用Handle方法。

如果您喜欢这种方法,可以提出来,简化数据结构并将CanHandledata转换为IDictionary

IList

在这种情况下,无 public interface IDataSub { object GetValue(); } public class DataSub<T> : IDataSub { private T _cache; public T Value { get { return _cache; } set { _cache = value; } } public object GetValue() { return Value; } } public interface IDataHandler { bool CanHandle(object data); void Handle(object data); } public class Client { private readonly IList<IDataSub> data = new List<IDataSub>(); private readonly IList<IDataHandler> handlers = new List<IDataHandler>(); public void AddData<T>(T someValueOfTypeT) { data.Add(new DataSub<T> { Value = someValueOfTypeT }); } public void RegisterHandler(IDataHandler handler) { handlers.Add(handler); } public void UseData() { foreach(var dataItem in data) { var value = dataItem.GetValue(); handlers.FirstOrDefault(h => h.CanHandle(value))?.Handle(value); } } // Lambda-free version as above... class StringDataHandler : IDataHandler { public bool CanHandle(object data) { // Your logic to check if this handler implements logic applyable to instances of String return data is string; } public void Handle(object data) { string value = (string) data; // Do something with string } } class IntDataHandler : IDataHandler { public bool CanHandle(Type type) { // Your logic to check if this handler implements logic applyable to instances of int return type is int; } public void Handle(object data) { int value = (int) data; // Do something with int } } 的变体也可以简化CanHandle接口及其实现...

我希望我的回答可以帮助您解决设计方案;我建立在我非常喜欢的方法的基础上,因为它允许将特定于子类型的逻辑应用于不同类的实例,因为它们共享一个共同的超类(如我的代码示例中的IDataHandler)。