简体   繁体   中英

Generic Method with optional generic parameter

How do I create a generic method with an optional generic type? This is what I have right now, which works

 public GridViewColumn<T> Column<D>(String HeaderText, D decorator) where D: IColumnDecorator, new()
        {
            GridViewColumn<T> column = new GridViewColumn<T>();
            column.HeaderText = HeaderText;
            column.Decorator = new D();
            return column;
        }

As you can see, I need to instantiate the type D (implements IColumnDecorator) inside the Column() method.

The issue is, the type "D" is optional. If Null, I want to explicitly use a default ColumnDecorator that I have. something like

 public GridViewColumn<T> Column<D>(String HeaderText, D decorator) where D: IColumnDecorator, new()
        {
            GridViewColumn<T> column = new GridViewColumn<T>();
            column.HeaderText = HeaderText;
            if(decorator ==null)
            {
               column.Decorator = new DefaultColumnDecorator();
            }
            else{
               column.Decorator = new D();
            }
            return column;
        }

Please help. Thanks!

[Edit].

Here is how I want to use it in razor MVC if I have a custom IColumnDecorator implementation

@Model.[IEnumerable].Grid(grid=>{
      ..
      ...
      grid.columns(
         grid.Column<MyOwnColumnDecorator>("FirstColumn")
      )
});

If I don't have any and want to use default, then I want to be able to do something like

@Model.[IEnumerable].Grid(grid=>{
          ..
          ...
          grid.columns(
             grid.Column("FirstColumn",null) or simply grid.Column("FirstColumn"); 
          )
    });

In your current code, you don't need the decorator parameter since you create a new instance of D and use that instead.

public GridViewColumn<T> Column<D>(String HeaderText) where D: IColumnDecorator, new()
{
    GridViewColumn<T> column = new GridViewColumn<T>();
    column.HeaderText = HeaderText;
    column.Decorator = new D();
    return column;
}

If you have a default parameter type to use, you don't need to use generics:

public GridViewColumn<DefaultColumnDecorator> Column(String headerText)
{
    return Column<DefaultColumnDecorator>(headerText);
}

Alternatively you could keep the parameter and remove the new() constraint:

public GridViewColumn<T> Column<D>(String HeaderText, D decorator) where D : IColumnDecorator
{
    GridViewColumn<T> column = new GridViewColumn<T>();
    column.HeaderText = HeaderText;
    column.Decorator = decorator;
    return column;
}

public GridViewColumn<DefaultColumnDecorator> Column(String headerText)
{
    return Column(headerText, new DefaultColumnDecorator());
}

Use a default parameter:

public GridViewColumn<T> Column<D,T>(string HeaderText, D decorator = null)
    where D : IColumnDecorator, class, new()

You shouldn't be instantiating type D from the Column method. Instead, you should let the caller pass it in.

 public GridViewColumn<T> Column(String HeaderText, IColumnDecorator decorator) 
        {
            GridViewColumn<T> column = new GridViewColumn<T>();
            column.HeaderText = HeaderText;
            if(decorator ==null)
            {
               column.Decorator = new DefaultColumnDecorator();
            }
            else{
               column.Decorator = decorator;
            }
            return column;
        }

The rationale is here: http://en.wikipedia.org/wiki/Dependency_injection

After playing with some options I made a sample that works with the following code:

public GridViewColumn<TResult> Column<TColumn>(string HeaderText, TColumn decorator = null) where TColumn : class, IColumnDecorator
{
    GridViewColumn<TResult> column = new GridViewColumn<TResult>();
    column.HeaderText = HeaderText;

     if(decorator == null)
     {
        column.Decorator = new DefaultColumnDecorator();
     }
     else
     {
        column.Decorator = decorator;  
     }     

    return column;
}

In order to make this work you need to consider the following:

  • You need to add the class restriction in order to be able to define your parameter as null.
  • You should not use default(TColumn) since it will return null because of the class restriction.
  • For some reason if you use the "? :" syntax the compiler does not accept that you instantiate the DefaultColumnDecorator type but if you use a regular if statement it works.
  • It seems the new() restriction is not necessary for this to work.

In my sample I was able to call this method in the following two ways with the same result:

@Model.[IEnumerable].Grid(grid=>{
      ..
      ...
      grid.columns(
         grid.Column<MyOwnColumnDecorator>("FirstColumn",null);
      )
});

@Model.[IEnumerable].Grid(grid=>{
      ..
      ...
      grid.columns(
         grid.Column<MyOwnColumnDecorator>("FirstColumn");
      )
});

Good luck!

There's a lot of ways to do what you're trying to do, how about asking the caller to pass a way to make a decorator?

public GridViewColumn<T> Column(string HeaderText, Func<IColumnDecorator> decoratorGenerator)
{
  GridViewColumn<T> column = new GridViewColumn<T>();
  column.HeaderText = HeaderText;
  column.Decorator = decoratorGenerator != null ? decoratorGenerator()
    : new DefaultColumnDecorator() ;
  return column;
}

I see two things you are missing. One is a default parameter setting decorator = null and the other is the use of default(T) . I have rewrote yours as follows but I can't test it obviously - should be close though.

public GridViewColumn<TResult> Column<TColumn>(string HeaderText, TColumn decorator = null) where TColumn : IColumnDecorator, new()
{
    GridViewColumn<TResult> column = new GridViewColumn<TResult>();
    column.HeaderText = HeaderText;
    column.Decorator = decorator == null ? new DefaultColumnDecorator() : default(TColumn);

    return column;
}

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