5

文字列から 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;
4

5 に答える 5

2

リフレクションを使用する例:

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 });
    }
}
于 2013-04-20T01:20:52.883 に答える
2

また、@Jon Skeet からのこの回答IsAssignableFromと、具体的には についての引用もご覧ください。

あなたが思い描いていた方法では、それは不可能だと思います。

Foo クラスに「インターフェイス コントラクト」を配置してから、ジェネリックに作業を任せることをお勧めします。

たとえば、このようなものですが、これは私が入力した迅速な解決策です...

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);
}

have that luxuryまた、タイプなどを知っていれば、同様の方法で呼び出すことができます
(ただし、これを解決して、必要に応じて調整できます)

Foo foo = Get<Foo, string>("another text");
于 2013-04-19T22:52:47.710 に答える
1

経由(object)すると、タイプチェックキャストまたはボックス/アンボックス(IL用語では、アンボックス-エニー)が実行されます-演算子は使用されません。(dynamic)ジェネリックと演算子を一緒に使用する唯一の方法は、の代わりに経由することです(object)が、これは実行時に少しは機能します。

于 2013-04-19T22:47:41.203 に答える
0

これは本当に醜いですが、テストはパスします:

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);
    }
}

クラスでジェネリックを定義し、ジェネリック関数をその抽象クラスに制約することにより、ジェネリックTを明示的にキャストできることをコンパイラーに認識させることができます。stringabstractCanCastFromStringGet()

于 2013-04-19T22:52:17.490 に答える
0

クラスで 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");
        }
    }
}

Du の質問で、変換できない場合は null を返すのと同じように、変換が無効な場合は null を返します。文字列の場合、これは限られたシナリオで機能します。このas演算子は、ユーザー定義の変換演算子も使用しません。

于 2013-04-19T22:56:47.840 に答える