C# 泛型显式转换

C# 泛型显式转换,c#,generics,casting,C#,Generics,Casting,我实现了从字符串到对象的显式转换,称为Foo 所以=>Foo f=(Foo)“Foo数据”;作品 我需要实现一个将字符串转换为泛型T的函数,在本例中,T是Foo数据类型 public T Get<T>(object o){ // this always return false if (typeof(T).IsAssignableFrom(typeof(String))) { // when i by pass the if

我实现了从字符串到对象的显式转换,称为Foo

所以=>Foo f=(Foo)“Foo数据”;作品

我需要实现一个将字符串转换为泛型T的函数,在本例中,T是Foo数据类型

public T Get<T>(object o){
      // this always return false
      if (typeof(T).IsAssignableFrom(typeof(String)))
      {
            // when i by pass the if above this throws invalid cast exception
            return (T)(object)str;
      }
      return null; 
}

// When I call this, it generated an error
// Invalid cast from 'System.String' to Foo
Foo myObj = Get<Foo>("another foo object"); 

// when I use the dynamic keyword it works but this is C# 4.0+ feature, my function is in the older framework
return (T)(dynamic)str;
publictget(对象o){
//这总是返回false
if(typeof(T).IsAssignableFrom(typeof(String)))
{
//当我绕过上面的if时,这会引发无效的强制转换异常
返回(T)(对象)str;
}
返回null;
}
//当我调用它时,它生成了一个错误
//从“System.String”到Foo的强制转换无效
Foo myObj=Get(“另一个Foo对象”);
//当我使用dynamic关键字时,它可以工作,但这是C#4.0+功能,我的功能在旧的框架中
返回(T)(动态)str;
如果通过
(对象)
执行类型检查强制转换或box/unbox(在IL术语中:unbox any)-它将不使用运算符。将泛型和运算符一起使用的唯一方法是通过
(动态)
而不是
(对象)
,但这在运行时会做一些工作。

这确实很难看,但测试通过了:

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest2
    {
        public T Get<T>(string str)
            where T : CanCastFromString<T>, ICanInitFromString, new()
        {
            return (T)str;
        }

        [TestMethod]
        public void Test()
        {
            var result = Get<Foo>("test");

            Assert.IsNotNull(result);
            Assert.IsInstanceOfType(result, typeof(Foo));
            Assert.AreEqual("test", result.Value);
        }
    }

    public class Foo : CanCastFromString<Foo>
    {
        public string Value { get; set; }

        public override void InitFromString(string str)
        {
            Value = str;
        }
    }

    public abstract class CanCastFromString<T> : ICanInitFromString
        where T : CanCastFromString<T>, ICanInitFromString, new()
    {
        public static explicit operator CanCastFromString<T>(string str)
        {
            var x = new T();
            x.InitFromString(str);
            return x;
        }

        public abstract void InitFromString(string str);
    }

    public interface ICanInitFromString
    {
        void InitFromString(string str);
    }
}
使用Microsoft.VisualStudio.TestTools.UnitTesting;
命名空间UnitTestProject1
{
[测试类]
公共类UnitTest2
{
公共T获取(字符串str)
其中T:CanCastFromString,icanitfromstring,new()
{
返回(T)str;
}
[测试方法]
公开无效测试()
{
var结果=获取(“测试”);
Assert.IsNotNull(结果);
IsInstanceOfType(result,typeof(Foo));
Assert.AreEqual(“测试”,result.Value);
}
}
公共类Foo:CanCastFromString
{
公共字符串值{get;set;}
公共重写void InitFromString(string str)
{
值=str;
}
}
公共抽象类CanCastFromString:ICanInitFromString
其中T:CanCastFromString,icanitfromstring,new()
{
公共静态显式运算符CanCastFromString(string str)
{
var x=新的T();
x、 InitFromString(str);
返回x;
}
公共抽象void InitFromString(string str);
}
公共接口ICanInitFromString
{
void InitFromString(string str);
}
}
通过在
abstract
CanCastFromString
上定义泛型
T
,然后约束
Get(),可以诱使编译器知道可以从
string
显式强制转换泛型
T
该抽象类的泛型函数。

还可以看一下@Jon Skeet中的内容,特别是关于
的引用是可从
中指定的

我认为这不可能以你想象的方式实现

我建议您在Foo类上设置一个“接口契约”,然后让泛型完成它们的工作

e、 类似这样的-但这只是我输入的一个快速解决方案

class Factory 
{
    public static T Create<T, TVal>(TVal obj) where T : class, IFoo<TVal>, new()
    {
        return new T { Value = obj }; // return default(T);
    }
}
interface IFoo<TVal>
{
    TVal Value { get; set; }
}
class Foo : IFoo<string>
{
    public string Value { get; set; }
    public Foo() { }
}
// ...
public T Get<T, TVal>(TVal obj) where T : class, IFoo<TVal>, new()
{
    return Factory.Create<T, TVal>(obj);
}

我假设您在类中定义了T,但无论如何,我都在方法中定义了T。如果您可以处理T上的类约束,那么这是有效的

namespace TestCast {
    class Program
    {
        public static T Get<T>(string o) where T : class
        {
            return o as T;
        }

        static void Main(string[] args)
        {
            Get<Breaker>("blah");
        }
    }
}
namespace TestCast{
班级计划
{
公共静态T Get(字符串o),其中T:class
{
返回o作为T;
}
静态void Main(字符串[]参数)
{
得到(“废话”);
}
}
}

如果转换无效,它将返回null,正如在杜的问题中,如果不能转换,他将返回null。对于字符串,这将在有限的场景中工作。
as
运算符也将使用用户定义的转换运算符。

使用反射的示例:

class Program
{
    static void Main(string[] args)
    {           
        Foo myObj = TypeResolver.Get<Foo>("Foo data");            
    }
}

class TypeResolver
{
    public static T Get<T>(object obj)
    {
        if (typeof(T).CanExplicitlyCastFrom<string>())
        {                             
            return obj.CastTo<T>();
        }
        return default(T);
    }
}

public static class Extensions
{
    public static bool CanExplicitlyCastFrom<T>(this Type type)
    {
        if (type == null)
            throw new ArgumentNullException("type");

        var paramType = typeof(T);
        var castOperator = type.GetMethod("op_Explicit", 
                                        new[] { paramType });
        if (castOperator == null)
            return false;

        var parametres = castOperator.GetParameters();
        var paramtype = parametres[0];
        if (paramtype.ParameterType == typeof(T))
            return true;
        else
            return false;
    }

    public static T CastTo<T>(this object obj)
    {            
        var castOperator = typeof(T).GetMethod("op_Explicit", 
                                        new[] { typeof(string) });
        if (castOperator == null)
            throw new InvalidCastException("Can't cast to " + typeof(T).Name);
        return (T)castOperator.Invoke(null, new[] { obj });
    }
}
类程序
{
静态void Main(字符串[]参数)
{           
Foo myObj=TypeResolver.Get(“Foo数据”);
}
}
类类型解析器
{
公共静态T Get(对象obj)
{
if(typeof(T).CanExplicitlyCastFrom())
{                             
返回obj.CastTo();
}
返回默认值(T);
}
}
公共静态类扩展
{
公共静态bool CanExplicitlyCastFrom(此类型)
{
if(type==null)
抛出新的ArgumentNullException(“类型”);
var paramType=类型(T);
var castOperator=type.GetMethod(“op_Explicit”,
新[]{paramType});
if(castOperator==null)
返回false;
var parametres=castOperator.GetParameters();
var paramtype=参数[0];
if(paramtype.ParameterType==typeof(T))
返回true;
其他的
返回false;
}
公共静态T CastTo(此对象对象对象)
{            
var castOperator=typeof(T).GetMethod(“op_Explicit”,
新[]{typeof(string)});
if(castOperator==null)
抛出新的InvalidCastException(“无法强制转换为”+typeof(t).Name);
return(T)castOperator.Invoke(null,new[]{obj});
}
}

您应该使用
类型转换器
s。Foo的定义是什么?它是否重载了
隐式
()或
显式
()运算符?@CodingWithSpike Foo具有显式转换Foo itm=(Foo)“string”编译器似乎不知道
t
将有用户提供的
显式
运算符,因此简单地强制转换
(t)str
将无法编译。如果您将泛型约束为
Foo
,那么它可以正常构建和工作,但这违背了泛型的目的,因为您只能指定
Foo
。正在寻找一种方法来欺骗编译器,使其允许…@AaronLS无法编译。我在最后一行中提到,dynmic是c#4.0功能,我被困在旧框架中。@DuD。那么你就不能通过泛型来实现它;这是唯一的办法。泛型的要点是
class Program
{
    static void Main(string[] args)
    {           
        Foo myObj = TypeResolver.Get<Foo>("Foo data");            
    }
}

class TypeResolver
{
    public static T Get<T>(object obj)
    {
        if (typeof(T).CanExplicitlyCastFrom<string>())
        {                             
            return obj.CastTo<T>();
        }
        return default(T);
    }
}

public static class Extensions
{
    public static bool CanExplicitlyCastFrom<T>(this Type type)
    {
        if (type == null)
            throw new ArgumentNullException("type");

        var paramType = typeof(T);
        var castOperator = type.GetMethod("op_Explicit", 
                                        new[] { paramType });
        if (castOperator == null)
            return false;

        var parametres = castOperator.GetParameters();
        var paramtype = parametres[0];
        if (paramtype.ParameterType == typeof(T))
            return true;
        else
            return false;
    }

    public static T CastTo<T>(this object obj)
    {            
        var castOperator = typeof(T).GetMethod("op_Explicit", 
                                        new[] { typeof(string) });
        if (castOperator == null)
            throw new InvalidCastException("Can't cast to " + typeof(T).Name);
        return (T)castOperator.Invoke(null, new[] { obj });
    }
}