Reputation: 5310
I implemented an explicit conversion from string to object called Foo.
So => Foo f = (Foo)"foo data"; works
I need to implement a function that cast a string to the generic T, T in this case is Foo datatype.
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;
Upvotes: 6
Views: 5208
Reputation: 2104
An example that uses Reflection:
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 });
}
}
Upvotes: 3
Reputation: 38392
I assume you defined T at the class, but either way I have it on the method. This works if you can handle a class constraint on 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");
}
}
}
It returns null if the conversion is not valid, just as in Du's question he returns null if can't convert. For a string, this will work in limited scenarios. The as
operator will also not utilize user defined conversion operators.
Upvotes: 0
Reputation: 43748
This is reallllly ugly, but the test passes:
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);
}
}
You can trick the compiler into knowing that your generic T
can be explicitly cast from string
by defining it on an abstract
class CanCastFromString
then constraining your Get()
generic function to that abstract class.
Upvotes: 0
Reputation: 14312
Also take a look at this answer from @Jon Skeet - and specifically the quote about IsAssignableFrom
.
I don't think that's possible in a way that you envisioned it.
I'd suggest you put an 'interface contract' on your Foo classes - and then let generics do their work.
e.g. something like this - but this is just a fast solution I typed in...
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);
}
And you can call it in a similar way - providing that you have that luxury
- know the types etc.
(but you can work this out and adjust if needed)
Foo foo = Get<Foo, string>("another text");
Upvotes: 2
Reputation: 1064184
If you go via (object)
then it just does a type-check cast or a box/unbox (in IL terms: an unbox-any) - it will not use operators. The only way to use generics and operators together is via (dynamic)
instead of (object)
, but this does a little work at runtime.
Upvotes: 1