简体   繁体   中英

c# Cannot convert anonymous type decimal? [] to decimal array

I am have implemented ac# linq expression which returns a decimal nullable array. I basically need to pass it to a function that accepts decimal array

I am getting error

Cannot convert anonymous type decimal? [] to decimal array.

var benchMark1Returns = GetViewService<MV_INDEX_PERFORMANCE>()
    .Where(x => x.IndexId == benchMark1 && x.PriceDate.Year == year)
    .Select(x => new { x.Mtd}).ToArray();

var benchMark2Returns = GetViewService<MV_INDEX_PERFORMANCE>()
    .Where(x => x.IndexId == benchMark2 && x.PriceDate.Year == year)
    .Select(x => new { x.Mtd }).ToArray();

var compoundReturnsBenchMark1 = CompoundReturns(benchMark1Returns);

The method that accepts decimal array

public static decimal? CompoundReturns(decimal[] rtns)
{
    if (rtns.Length == 0)
        return null;

    return rtns.Aggregate((decimal)1, (acc, val) => acc * (1 + val)) - 1;
}

First, you don't want a collection of an anonymous type:

.Select(x => new { x.Mtd })

You just want the decimal:

.Select(x => x.Mtd)

But furthermore, it's also telling you that Mtd is a decimal? , not a decimal . The former can not be directly converted to the latter because the former supports values the latter does not. (ie null )

So either you'll need to define a default value when Mtd is null :

.Select(x => x.Mtd ?? 0M)

or change your method to accept a decimal?[] :

public static decimal? CompoundReturns(decimal?[] rtns)

Note that in that last case you will also need to update your method to support a null value. For example, changing the type to which you case 1 in the Aggregate() call:

rtns.Aggregate((decimal?)1, (acc, val) => acc * (1 + val)) - 1;

When you call new { x.Mtd } , you are instructing the compiler to create a new, anonymous type which as a single property, called Mtd , which contains the decimal value. Naturally, this isn't a decimal[] , it's a MyType[] .

Since it doesn't seem like you're actually using that anonymous type for anything, you should simply return the decimal value itself, instead of the anonymous type:

.Select(x => x.Mtd)

.Select(x => new { x.Mtd}) create a new anonymous object. You just want the property value:

.Select(x => x.Mtd)

If Mtd can be null and you wish to filter out the null values, use this:

.Where(x => x.Mtd != null).Select(x => x.Mtd.Value).ToArray();

You have to make two changes:

First remove anonymous type. Then for select

.Select( x=> x.Mtd ?? 0);

This will allow you to pass decimal[] as paramter without changing the current method.

Else, you have to do:

 .Select(x =x.Mtd) 

And change the method parameter to have nullable decimal array. Hope it is ok

In addition to my earlier comment, viz

assuming x.Mtd is decimal , then just remove the new {} ie (x => x.Mtd).ToArray()

The bigger problem though is that your database has nulls in it, when it really shouldn't - the consequences of a null index performance in a for a period in a compound returns chart would be catastrophic for the compound returns - a missing data point would invalidate all future data points.

So the real solution is to find any null datapoints in the data source and provide the correct data for them.

Then change the data type of Mtd on the Dto returned from GetViewService from

 decimal? Mtd 

to

decimal Mtd

(ie disallow nulls).

Then all that is needed to your original code is to remove the anonymous class projection, ie

.Where(x => x.Mtd != null)
.Select(x => x.Mtd.Value)
.ToArray();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM