-1

Below is my method which is calling two delegate function which in turn return two keys partition and Row key. the methods are same for generating partition and Row key and only difference is which string from list returned to be taken as row key and partition key. I would like to know if there is way I can optimize my below method and use one delegate function instead of two.How do i do it?( if possible someone can show me).

// first strarting point
    await csvCopy.UploadNCsvData( rule.GeneratePartitionKey,rule.GenerateRowKey, unzipper, schemaFormat, true, csvSchema );
           

then defining upload

public async Task UploadNCsvData( Func<Dictionary<string, EntityProperty>, Task<string>> genPartitionKey,
                Func<Dictionary<string, EntityProperty>, Task<string>> genRowKey,
                Stream lines, string format, bool upsert, IDataClassifier classifier )
            {
                //mycode and then finally calling WriteToTable()
                await WriteToTable( lines, dataclass,
                    genPartitionKey,
                    genRowKey, upsert );
            }

//finally the writeToTable()

public async Task WriteToTable( Stream lines, DataClass dataclass,
           Func<Dictionary<string, EntityProperty>, Task<string>> genPartitionKey,
            Func<Dictionary<string, EntityProperty>, Task<string>> genRowKey, bool upsert )
        {
            const int BatchSize = 100;
            if( HasPartitionAndRowKey( dataclass.TableSchema.Fields ) )
            {
                genPartitionKey = ( Dictionary<string, EntityProperty> props ) => Task.FromResult(props["PartitionKey"].StringValue);
                genRowKey = ( Dictionary<string, EntityProperty> props ) => Task.FromResult(props["RowKey"].ToString());
            }
            
            var tableRecords = ReadCSV( lines, dataclass.TableSchema.Fields )
                .Select( async props => new DynamicTableEntity( await genPartitionKey( props ), await genRowKey( props ), string.Empty, props ) )
                .ToList();
            await BatchInsertIntoTableStorage( BatchSize, tableRecords, upsert );

        } 



 

private IEnumerable<Dictionary<string, EntityProperty>> ReadCSV( Stream source, IEnumerable<TableField> cols )
        {
            using( TextReader reader = new StreamReader( source, Encoding.UTF8 ) )
            {.....
    .......
     while( csv.Read() )
                {
                    yield return map.ToDictionary(
                        col => col.Name,
                        col => EntityProperty.CreateEntityPropertyFromObject( csv.GetField( col.Type, col.Index ) ) );
                }
            }
        }

// These are functions being called and as you see the methods and arguments are same, only return value differ in which string to pass.

 internal async Task<string> GeneratePartitionKey( Dictionary<string, EntityProperty> arg)
    {       
        var result =await GenerateKeys(arg);
        return result[0].ToString();
    }        

    internal async Task<string> GenerateRowKey( Dictionary<string, EntityProperty> arg )
    {
        var result = await GenerateKeys( arg );
        return result[1].ToString();
    }
ZZZSharePoint
  • 1,163
  • 1
  • 19
  • 54
  • 1
    The code displayed has the same return type look the same `Task` – Orel Eraki Feb 24 '21 at 07:47
  • _"only return type differ in which string to pass."_ They don't differ in return _type_. They differ in one single parameter. Is there a reason you are using delegates in the first place? And if `GenerateKeys` work on the same input (which they are) and thus generate the same output (which they _should_), you could just do that in one function and return both strings at once. – Fildor Feb 24 '21 at 07:57
  • this is an existing code where some modification is done so will keep the delegates, and...yes that was wrong wording, its doesnt differ on type – ZZZSharePoint Feb 24 '21 at 08:01
  • 1
    edited and added the calls – ZZZSharePoint Feb 24 '21 at 08:18
  • You could introduce a parameter for `0` or `1`. Then pass only one function pointer and use a constant or enum to distinguish their semantics. – Thomas Weller Feb 24 '21 at 08:35
  • can you please show me and post it as an answer – ZZZSharePoint Feb 24 '21 at 08:36

1 Answers1

1

How about returning a ValueTuple?

internal async Task<(string, string)> GenerateKeys(Dictionary<string, EntityProperty> arg)
{
    var result = await GenerateKeys(arg);
    return (result[0].ToString(), result[1].ToString());
}

Usage:

public async Task WriteToTable(Stream lines, DataClass dataclass,
    Func<Dictionary<string, EntityProperty>, Task<(string, string)>> genKeys, bool upsert)
{
    ...
    if (HasPartitionAndRowKey(dataclass.TableSchema.Fields))
    {
        genKeys = props => Task.FromResult((props["PartitionKey"].StringValue, props["RowKey"].ToString()));
    }

    ...
    var tableRecords = ReadCSV(lines, dataclass.TableSchema.Fields)
        .Select(async props =>
        {
            var (partitionKey, rowKey) = await genKeys(props);
            return new DynamicTableEntity(partitionKey, rowKey, string.Empty, props);
        })
        .ToList();
    ...
}

Please read this topic to understand how to use async-await in Select.

Peter Csala
  • 17,736
  • 16
  • 35
  • 75
  • what about the line genPartitionKey and genRowKey inside HasPartitionAndRowKey in WritToTable. I changed to "genKeys = ( Dictionary props ) => Task.FromResult(props["PartitionKey"].StringValue.ToString(), props["RowKey"].ToString());" but it says error No Overload takes two results – ZZZSharePoint Feb 24 '21 at 11:04
  • 1
    @ZZZSharePoint One pair of parenthesis are missing: `Task.FromResult((props["PartitionKey"].StringValue.ToString(), props["RowKey"].ToString()));` I've extended my answer to include that piece as well. – Peter Csala Feb 24 '21 at 11:06