Mapster icon indicating copy to clipboard operation
Mapster copied to clipboard

ConstructUsing for generic types doesn't work

Open omerercelik opened this issue 3 years ago • 10 comments

TypeAdapterConfig<PagedList<ExampleEntity>, PagedList<ExampleDto>>.ForType().ConstructUsing(dest => new PagedList<ExampleDto>(new List<ExampleDto>(), 1, 1)); = > its work

TypeAdapterConfig<PagedList<Type>, PagedList<Type>>.ForType().ConstructUsing(dest => new PagedList<Type>(new List<Type>(), 1, 1)); it doesn't work and throw Exception

Exception => System.InvalidOperationException : No default constructor for type 'PagedList`1', please use 'ConstructUsing' or 'MapWith'

pagedlist constructors;

    `public PagedList(IEnumerable<T> items, int page, int size)
        : this(items.AsQueryable(), page, size)
    {
    }

    public PagedList(IEnumerable<T> items, int page, int size, int itemCount)
    {
        BindItems(page, size, itemCount);
        Items = items;
    }

    public PagedList(IQueryable<T> items, int page, int size)
    {
        var itemCount = items.Count();
        BindItems(page, size, itemCount);

        Items = items.PagedBy(page, size).ToList();
    } `

omerercelik avatar Dec 12 '22 09:12 omerercelik

@omerercelik Which version of Mapster are you using?

andrerav avatar Jan 03 '23 21:01 andrerav

@andrerav I am using 7.3.0

omerercelik avatar Jan 03 '23 22:01 omerercelik

@omerercelik You can set Full sample of this case. propably i found the source of this problem )

DocSvartz avatar Oct 23 '23 18:10 DocSvartz

@andrerav This seems to be related to the reason why the tests I commented out in this do not work #646 . the same error is generated there. I made a simplified version of the bypass previously installed in the class adapter and then there was no error.

DocSvartz avatar Oct 23 '23 18:10 DocSvartz

TypeAdapterConfig<PagedList<Type>, PagedList<Type>>.ForType().ConstructUsing(dest => new PagedList<Type>(new List<Type>(), 1, 1)); it doesn't work and throw Exception

If Type is System.Type? then as far as I understand it cannot be created. This can only be obtained. typeof(), .Gettype()

valid Generic definition possible must look like as typeof(PagedList<>), and mapping from this and mapping for this should be supported endofpage

TypeAdapterConfig.GlobalSettings.ForType(typeof(GenericPoco<>), typeof(GenericDto<>))
    .Map("value", "Value");

DocSvartz avatar Oct 24 '23 01:10 DocSvartz

TypeAdapterConfig.GlobalSettings.ForType(typeof(GenericPoco<>), typeof(GenericDto<>)) Does not have ConstructUsing definition. @DocSvartz When I use this syntax i can not use ConstructUsing method.

How can I use contructusing method in generic classes? Or How can i skip this error when generic class have one more constructor?

Exception => System.InvalidOperationException : No default constructor for type 'PagedList`1', please use 'ConstructUsing' or 'MapWith'

omerercelik avatar Oct 25 '23 05:10 omerercelik

Even if you bring it to a case that in theory should work.

You get IQueryable from the conversion function and there will always be an error Instead of the data you need

[TestClass]
public class WhenGenericMapping
{


    [TestMethod]
    public void TestMappingGeneric()
    {
        TypeAdapterConfig
            .GlobalSettings
            .ForDestinationType(typeof(SamplePageList<>))
            .MapToConstructor(true);

        SamplePageList<string> _SourcePageList = new(new[] { "1234", "222" }.ToList(), 2, 2);
                  
         var _DeconstructPageList = _SourcePageList.Adapt<PocoActivatorPageList<string>>();
         var _result = _DeconstructPageList.Adapt<SamplePageList<string>>();

        _DeconstructPageList.Items.ToArray()[0].ShouldBe("1234"); 
        _DeconstructPageList.Items.ToArray()[1].ShouldBe("222"); 

        _result.Items.ToArray()[0].ShouldBe("1234"); // Error 
        _result.Items.ToArray()[1].ShouldBe("222"); //  Error 

    }

}


    class PocoActivatorPageList<T>
    {
        public  IEnumerable<T> Items { get; set; }
        public int Size { get; set; }
        public int Page { get; set; }

    }


    class SamplePageList<T>
    {

        public IQueryable<T> Items { get;  private set; }

        public int Size {  get; private set; }
        public int Page {  get; private set; }

        public int ItemCount { get; private set; }

        public SamplePageList(IEnumerable<T> items, int page, int size)
        : this(items.AsQueryable(), page, size)
        {
            // this target
        }

        public SamplePageList(IEnumerable<T> items, int page, int size, int itemCount)
        {
           /// Not used
        }

        public SamplePageList(IQueryable<T> items, int page, int size)
        {
            Items = items;
            ItemCount = items.Count();
            Page = page;
            Size = size;
        } 
    }


Error Message:
 System.NotImplementedException: The method or operation is not implemented.
Trace Stack:
  GeneratedType_1.GetEnumerator()
  LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
  EnumerableHelpers.ToArray[T](IEnumerable`1 source)
  Enumerable.ToArray[TSource](IEnumerable`1 source)
  WhenGenericMapping.TestMappingGeneric() 

From this File Mapster.Utils.DynamicTypeGenerator

DocSvartz avatar Oct 25 '23 13:10 DocSvartz

@andrerav For some reason, RecordType is involved there again))) for interface IQueryable

DocSvartz avatar Oct 25 '23 15:10 DocSvartz

@andrerav Apparently it is necessary to allocate a separate InterfaceAdapter (Base logic work from all Interface) handler with private setters (uses from RecordTypeAdapter). I'll try this as step 3 of fix #537. In continuation of this PR #646.

DocSvartz avatar Oct 26 '23 02:10 DocSvartz

@omerercelik This working From This

@andrerav I managed to separate the processing of interfaces without public setters from the processing of RecordTypes)

But IQueryable now not supported

[TestClass]
public class WhenGenericMapping
{


    [TestMethod]
    public void TestMappingGeneric()
    {

        TypeAdapterConfig
            .GlobalSettings
            .ForType(typeof(SamplePageList<>), typeof(SamplePageList<>))
            .ShallowCopyForSameType(true);

        SamplePageList<string> _SourcePageList = new(new[] { "1234", "222" }.ToList(), 2, 2);
        SamplePageList<int> _SourcePageList2 = new(new[] { 555, 333 }.ToList(), 2, 2);
                   
        var c = _SourcePageList.Adapt(_SourcePageList2);

        c.Items.ToArray()[0].ShouldBe(1234);
        c.Items.ToArray()[1].ShouldBe(222);

    }

}


class PocoActivatorPageList<T>
{
    public  IEnumerable<T> Items { get; set; }
    public int Size { get; set; }
    public int Page { get; set; }

}


class SamplePageList<T>
{

    public IEnumerable<T> Items { get;  private set; }

    public int Size {  get; private set; }
    public int Page {  get; private set; }

    public int ItemCount { get; private set; }

    public SamplePageList(IEnumerable<T> items, int page, int size)
        
    {
        Items = items;
        ItemCount = items.Count();
        Page = page;
        Size = size;
    }

    public SamplePageList(IEnumerable<T> items, int page, int size, int itemCount)
    {
       /// Not used
    }

    public SamplePageList(IQueryable<T> items, int page, int size)
    {
        Items = items;
        ItemCount = items.Count();
        Page = page;
        Size = size;
    } 
}


DocSvartz avatar Oct 26 '23 12:10 DocSvartz