【问题标题】:C# casting object to class with type argumentC# 将对象转换为具有类型参数的类
【发布时间】:2016-09-08 23:40:03
【问题描述】:

我有一个名为 Property 的类,它存储一个值并在值更改时引发一个事件。有一个名为 Observable 的不同类,我想包含一个属性字典,下面有一个示例。如何获取存储在字典中的属性类型以便修改对象?

属性类:

public class Property<T>
{
     public T Value { get; set; }
}

可观察类:

public class Observable
{
    public readonly Dictionary<string, object> 
              Properties = new Dictionary<string, object>();

    public Property<T> Get<T>(string name)
    {
        object obj;
        Properties.TryGetValue(name, out obj);
        return (Property<T>) obj;
    }
}

编辑这是我得到的错误 - 未处理的异常:System.InvalidCastException:无法将“System.String”类型的对象转换为“ConsoleApplication.Property`1[System.String]”类型。

另外,如果我可以摆脱 Get 函数并将其替换为不需要知道类型的东西会好得多。

更新:有没有办法通过将名称与类型进行散列来获取类型?

【问题讨论】:

  • 您想假设Get&lt;T&gt;(...) 会成功吗?您提供的代码有什么问题?
  • 这不是我要问的。我不想获取字典值的类型,我想获取属性中值的类型。
  • 那么,你想要return GetType(obj); 的东西吗?
  • 我们知道字典中的所有对象都是 Property 类型,但是我们不知道 T 是什么。即使我说什么 T 是一个错误也会被抛出。例如,如果我将 Property Get 更改为 Property

标签: c# casting


【解决方案1】:

编辑(更新帖子):

有没有办法通过使用类型对名称进行散列来获取类型?

这是你想要的吗? dotnetfiddle link

public interface IProperty
{
    object Value { get; }
    Type TypeOfValue { get; }
}

public class Property : IProperty
{
    public object Value { get; set; }
    public Type TypeOfValue { get; set; }
    public override string ToString() { return TypeOfValue.FullName + ": " + Value; }
}

public class Observable
{
    public readonly Dictionary<string, Property> 
        Properties = new Dictionary<string, Property>();

    // use interface so consumer of your property can't mess with the
    // type or value stored in your dictionary within Observable
    public IProperty Get(string name)
    {
        Property obj;
        if (Properties.TryGetValue(name, out obj)){
            return obj;
        }

        // throw something which makes more sense to you
        throw new ArgumentException(name + " does not exist in the dictionary");
    }

    // sample of how you'd store these properties
    public void Set(string name, object val)
    {
        if (Properties.ContainsKey(name)){
            Properties[name].Value = val;
            Properties[name].TypeOfValue = val.GetType();
        } else {
            Properties[name] = new Property {
                Value = val,
                TypeOfValue = val.GetType()
            };
        }
    }
}

原始答案:

您可能不小心将string 插入到Observable 内部的字典中,而不是Property&lt;string&gt;,如果是这样,问题不在您发布的代码中,而是在您发布的任何地方'正在插入 string 而不是 Property&lt;string&gt;

如果您不喜欢无效的强制转换异常,有两种解决方案。

解决方案 1:自定义函数抛出的错误。

如果您想保留Get&lt;T&gt;(...) 的签名,我建议您进行一些错误处理。您看到的错误是因为您的字典中的属性是string 类型,而不是Property&lt;string&gt; 类型。以下代码将为您提供一些可用于更多错误处理的东西。

public class Observable
{
    public readonly Dictionary<string, object> 
        Properties = new Dictionary<string, object>();

    public Property<T> Get<T>(string name)
    {
        object obj;
        if (Properties.TryGetValue(name, out obj)){
            try {
                return (Property<T>) obj;
            } catch(InvalidCastException){
                // throw something which makes more sense to you
                throw new ArgumentException("Could not cast the given object to the desired type");
            }
        }

        // throw something which makes more sense to you
        throw new ArgumentException(name + " does not exist in the dictionary");
    }
}

解决方案2:返回一般object

public class Observable
{
    public readonly Dictionary<string, object> 
        Properties = new Dictionary<string, object>();

    public object Get(string name)
    {
        object obj;
        if (Properties.TryGetValue(name, out obj)){
            return obj;
        }

        // or do whatever you want when the given key doesn't exist.
        return null;
    }
}

【讨论】:

    【解决方案2】:

    索引器可以在不使用其他构造的情况下解决您的问题。 看看你是否是我不确定我是否让你清楚,但我会尽力提供帮助) 至于我,这个问题可以改写如下。 是否可以确定向上转换类型的最具体类型。

    这是一个可以帮助你的代码

     public class Employee
    {
        public int salary { get; set; }
    
    }
    
    public class Manager : Employee
    {
    
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            Manager man = new Manager();
            System.Object emp = (object) man;
            Console.WriteLine(emp.GetType());
        }
    }
    

    WriteLine 操作的输出是“Project_Name”.Manager,因此您可以看到最初在内存中分配的类型。不熟悉他们。

    【讨论】:

      猜你喜欢
      • 2021-08-11
      • 2016-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多