Explicit Conversion Operator Error When Converting Generic Lists

explicit conversion operator error when converting generic lists

The error "User-defined conversion must convert to or from the enclosing type" says exactly what it means. If you have a conversion operator

class MyClass {
public static explicit operator xxx(string s) { // details }
public static implicit operator string(xxx x) { // details }
}

Then xxx must be MyClass. This is what is meant by the "conversion must convert to or from the enclosing type." The enclosing type here is MyClass.

The relevant section of the ECMA334 C# spec is 17.9.4:

A conversion operator converts from a source type, indicated by the parameter type of the conversion operator, to a target type, indicated by the return type of the conversion operator. A class or struct is permitted to declare a conversion from a source type S to a target type T only if all of the following are true, where S0 and T0 are the types that result from removing the trailing ? modifiers, if any, from S and T:

S0 and T0 are different types.

Either S0 or T0 is the class or struct type in which the operator declaration takes place.

Neither S0 nor T0 is an interface-type.

Excluding user-defined conversions, a conversion does not exist from S to T or from T to S.

So here's your code:

public static explicit operator List<Model.objA>(List<Entity.objA> entities) {
List<Model.objA> objs= new List<Model.objA>();
foreach (Entity.objA entity in entities) {
objs.Add((Model.objA)entity);
}
return claims;
}

The issue is that for this to be defined as a conversion operator it must reside in the List<Model.objA> or List<Entity.objA> classes but of course you can not do that as you don't have access to change those types.

You could use Enumerable.Select to project to the other type, or List<T>.ConvertAll. For example:

public static class ListExtensions {
public static List<Model.objA> ConvertToModel(this List<Entity.objA> entities) {
return entities.ConvertAll(e => (Model.objA)e);
}
}

How can convert a List to another List with explicit operator with out using extention method

You can't use Conversion Operators for converting list of one type to another.

C# enables programmers to declare conversions on classes or structs so
that classes or structs can be converted to and/or from other classes
or structs, or basic types.

As you see, the purpose is to convert one type to another, not the list of that types.

You can use Select method instead of that:

List<B> listB = listA.Select(a => (B)a).ToList();

Generics explicit conversion

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

How to call type conversion operator in C# generic class?

If you need to have your custom implicit/explicit conversion operators run, then casting to/from object (or performing an as cast) will skip them because the information is only known at compile-time when you are performing a runtime cast.

The only way I know of, through a general-use generic method such as you posted, is to leverage dynamic which will lookup at runtime to see if there are any conversion operators defined and call them:

return (T2)(dynamic)obj;

Quick example:

public class Class1
{

public static implicit operator Class1(Class2 class2)
{
Console.WriteLine("implicit conversion from Class2 to Class1");
return new Class1();
}

public static implicit operator Class2(Class1 class1)
{
Console.WriteLine("implicit conversion from Class1 to Class2");
return new Class2();
}
}

public class Class2
{

}

public static T2 Convert<T1, T2>(T1 obj)
{
return (T2)(dynamic)obj;
}

var class1 = new Class1();
var class2 = Convert<Class1, Class2>(class1);
//outputs: implicit conversion from Class1 to Class2

Be aware though, that this using reflection and doing significant work at runtime, so thoroughly test and make sure performance is still acceptable.

EDIT: Since you do not have access to the dynamic language runtime, you can write your own conversion operator lookups with reflection:

public static T2 Convert<T1, T2>(T1 obj)
{
var conversionOperator = typeof(T1).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(m => m.Name == "op_Explicit" || m.Name == "op_Implicit")
.Where(m => m.ReturnType == typeof(T2))
.Where(m => m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(T1))
.FirstOrDefault();

if (conversionOperator != null)
return (T2)conversionOperator.Invoke(null, new object[]{obj});

throw new Exception("No conversion operator found");
}

You may need to tweak the code (perhaps to attempt traditional casting if no operators are found), and I'm not sure if I can guarantee that this will work every time. I don't know if there are corner cases or platform quirks to handle. Not to mention that this will be pretty slow with the reflection. You could introduce a quick caching mechanism where you do an O(1) lookup with a Dictionary or something where you can store each conversion operator as they're found for each type combination.

why does explicit cast for generic list not work

List<InteractionSegment> is not the same as InteractionSegment. Casting a list of one type to a list of another type won't cast each item.

You need to do something like this:

this.Segments = inEdges.Select(x => (InteractionSegment)x).ToList();

This uses LINQ to Objects to cast each object in inEdges to an InteractionSegment object and puts the result back into a list that is then assigned to this.Segments.

How to realize explicit and implicit type conversion for non-generic synonyms of generic struct?

The error

User-defined conversion must convert to or from the enclosing type.

means that your conversion operators need to convert to/from A<T>. Yours are converting to/from A<int/string>. That's not the same thing (much less general at least).

So this cannot work. You have to find some other way to do the conversions. Maybe runtime casting can help here (define the operators as acting on A<T> and do casting inside of them).

I think this problem is unrelated to the type synonyms. In fact they made the question harder to understand.



Related Topics



Leave a reply



Submit