c#转换为泛型类型

本文关键字:泛型类型 转换 | 更新日期: 2023-09-27 18:09:22

我已经编写了这些类来创建一个组合,它可以包含泛型类型和值。

似乎还好,但是当我想要合成时,我遇到了一个问题,将合成中的issomething转换为Something并获得其值。我不能将列表中的issomethings强制转换为它们的类型,例如:

这里有诀窍吗,还是不能做到??(应该怎么做??)谢谢肯尼斯·

public interface ISomething
{
  string Name { get; set; }
}
public class Something<T> : ISomething
{
   public string Name { get; set; }
   public T Value { get; set; }
   public Something(string name, T value)
   {
      Name = name;
      Value = value;
   }
}
public class CompositeSomething : Something<IList<ISomething>>
{
   public CompositeSomething (string name)
      : base(name, new List<ISomething>())
   {
   }
   public void Add(ISomething newSomething)
   {
      Value.Add(newComponent);
   }
   public void Remove(ISomething oldSomething)
   {
      Value.Remove(oldSomething);
   }
}

XmlNode BuildXml(Something something, XmlDocument document)
{
    XmlNode node = document.CreateNode(XmlNodeType.Element,
                   something.Name, "");
    foreach (ISomething item in compositeSomething.Value)
    {
        var isComposite = item is CompositeSomething;
        if (isComposite)
        {
            node.AppendChild(BuildXml((CompositeSomething)item, document));
        }
        else
        {
           var child = (Something<T>)item; // FAILS!!!!
           node.AppendChild(BuildXml(child,document));
        }
    }
    return node;
 }

c#转换为泛型类型

给你的非泛型接口也一个object类型的value属性,并显式地实现它:

public interface ISomething
{
  string Name { get; set; }
  object Value { get; }
}
public class Something<T> : ISomething
{
   public string Name { get; set; }
   public T Value { get; set; }
   public Something(string name, T value)
   {
      Name = name;
      Value = value;
   }
   public object ISomething.Value
   {
      get { return Value; }
   }
}

更新

没有内置机制将非泛型对象强制转换为泛型类型对象并直接访问其值。在这种情况下,您可以使用字典作为类型解析器(未经验证,直接写在这里,不需要编译器检查):

private Dictionary<Type, Action<ISomething>> _TypeResolver = new Dictionary<Type, Action<ISomething>>();
private void InitializeTypeResolver()
{
    _TypeResolver.Add(typeof(Something<int>), ForInteger);
    _TypeResolver.Add(typeof(Something<double>), ForDouble);
}
private void ForInteger(ISomething source)
{
    // We know, we will only be called for this specific type, so a hard cast is the way to go.
    var something = (Something<int>)source;
    var value = something.Value; // Will be of type int.
    // ToDo: Whatever you want with that integer.
}
private void ForDouble(ISomething source)
{
     var something = (Something<double>)source;
     var value = something.Value; // Will be of type double.
}
private void Resolve(ISomething something)
{
     // ToDo: nullity checks.
     Action<ISomething> action;
     if(_TypeResolver.TryGetValue(something.GetType(), out action))
     {
         action(something);
     }
     else
     {
         // ToDo: What shall we do with the drunken sailor (or unknown type)?             
     }
}

听起来这个问题只是给了一个ISomething如何访问这个值。

试试这个:

Something<int> something1 = new Something<int>("Foo", 42);
ISomething something = (ISomething)something1;
Something<int> something2 = something as Something<int>;
if (something2 != null)
{
    Console.WriteLine(something2.Value);
}

这是42

as Something<int>只有在原始实例为Something<int>时才会产生一个值,否则它将返回null

另一种方法是像这样扩展你的接口和实现:
public interface ISomething
{
    string Name { get; set; }
    object Value { get; }  
}
public class Something<T> : ISomething
{
    public string Name { get; set; }
    public T Value { get; set; }
    object ISomething.Value { get { return Value; } }
    public Something(string name, T value)
    {
        Name = name;
        Value = value;
    }
}

那么你可以写:

Something<int> something1 = new Something<int>("Foo", 42);
ISomething something = (ISomething)something1;
Console.WriteLine(something.Value);

再次给出42

您可以进一步扩展代码以提供值的类型,如:

public interface ISomething
{
    string Name { get; set; }
    object Value { get; }
    Type ValueType { get; }
}
public class Something<T> : ISomething
{
    public string Name { get; set; }
    public T Value { get; set; }
    object ISomething.Value { get { return Value; } }
    Type ISomething.ValueType { get { return typeof(T); } }
    public Something(string name, T value)
    {
        Name = name;
        Value = value;
    }
}

无论如何,你仍然需要使用反射来获取值,但是接口提供给你的值不需要反射。


下面是如何实现BuildXml

从这样的类开始:

public interface ISomething
{
    string Name { get; set; }
    object Value { get; }
    Type ValueType { get; }
}
public class Something<T> : ISomething
{
    public string Name { get; set; }
    public T Value { get; set; }
    object ISomething.Value { get { return Value; } }
    Type ISomething.ValueType { get { return typeof(T); } }
    public Something(string name, T value)
    {
        Name = name;
        Value = value;
    }
}
public class CompositeSomething : Something<IList<ISomething>>
{
    public CompositeSomething (string name)
        : base(name, new List<ISomething>())
    {
    }
    public void Add(ISomething newSomething)
    {
        Value.Add(newSomething);
    }
    public void Remove(ISomething oldSomething)
    {
        Value.Remove(oldSomething);
    }
}

你可以这样写BuildXml:

XElement BuildXml<T>(Something<T> something)
{
    var compositeSomething = something as CompositeSomething;
    if (compositeSomething != null)
    {
        MethodInfo z =
            this
                .GetType()
                .GetMethod("BuildXml", BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance);
        return
            new XElement(
                compositeSomething.Name,
                compositeSomething.Value
                    .Select(x => z.MakeGenericMethod(x.ValueType).Invoke(this, new object[] { x }) as XElement));
    }
    else
    {
        return new XElement(something.Name, something.Value);
    }
}

我选择使用LinqToXml来构建xml。

那么,给定这个输入:

var cs1 = new CompositeSomething("Foo");
cs1.Add(new Something<int>("Bar", 42));
cs1.Add(new Something<string>("Qaz", "Wix"));
var cs2 = new CompositeSomething("Rew");
cs2.Add(new Something<decimal>("Moo", 1.98m));
cs2.Add(cs1);

我可以运行BuildXml(cs2)来得到这个输出:

<Rew>
  <Moo>1.98</Moo>
  <Foo>
    <Bar>42</Bar>
    <Qaz>Wix</Qaz>
  </Foo>
</Rew>

我想这就是你想要的。

实现非泛型接口;

public interface IGetGenericTypeInstance
{
    object GenericTypeInstance();
}

现在我可以将对象强制转换为IGetGenericTypeInstance, GenericTypeInstance将返回属性作为类型对象。