【问题标题】:How can I create a public static method while implementing an interface in c#? [duplicate]如何在 C# 中实现接口时创建公共静态方法? [复制]
【发布时间】:2016-11-21 12:01:30
【问题描述】:

我有如下界面

public interface IQueryBuilder
{
    SqlCommand Build(IReportDataSource dataSource, List<IReportColumn> columns, List<IReportRelationMapping> relationMappings, IReportFilterMapping filters, List<IReportColumn> columsToSortBy, ReportFormat reportFormat);

    string GetSqlClause(List<IReportFilter> reportFilters, ref List<IDataParameter> sqlParams);
}

但是,我希望能够直接访问实现中的方法GetSqlClause

这是我实现上述的方法

public class QueryBuilder : IQueryBuilder
{
    public SqlCommand Build(IReportDataSource dataSource, List<IReportColumn> columns, List<IReportRelationMapping> relationMappings, IReportFilterMapping filters, List<IReportColumn> columsToSortBy, ReportFormat reportType)
    {
        //Do something awsome!!!
        string sqlQuery = "";

        List<IDataParameter> sqlParameters = new List<IDataParameter>();

        return this.GetSqlCommand(sqlQuery, sqlParameters);
    }

    private SqlCommand GetSqlCommand(string sqlQuery, List<IDataParameter> sqlParams)
    {
        var command = new SqlCommand(sqlQuery);

        foreach (IDataParameter dataParameter in sqlParams)
        {
            command.Parameters.Add(dataParameter);
        }

        return command;
    }


    public static string GetSqlClause(List<IReportFilter> reportFilters, ref List<IDataParameter> sqlParams)
    {
        string sqlFilter = "";

        if (reportFilters != null && reportFilters.Any())
        {
            //At this point we know there are some filter to add to the list

            var firstFilter = reportFilters.First();

            foreach (var reportFilter in reportFilters)
            {

                var parameter = GenerateDbParameter("p" + sqlParams.Count, reportFilter.FormattedValue, SqlDbType.NVarChar);
                ....
                ....
            }
        }

        return sqlFilter;
    }

    private static IDataParameter GenerateDbParameter(string parameterName, object parameterValue, SqlDbType parameterType)
    {
        if (string.IsNullOrEmpty(parameterName) || parameterValue == null)
        {
            throw new ArgumentException();
        }
        var parameter = new SqlParameter("@" + parameterName, parameterType)
        {
            Value = parameterValue
        };

        return parameter;
    }


}

因为我在我的 GetSqlClause 方法上使用了 static,所以我收到了一个错误

无法实现接口成员,因为它是静态的。

有什么好的方法可以解决这个问题?如何直接访问我的GetSqlClause

【问题讨论】:

  • 您希望它是静态的有什么原因吗?有必要吗?只是不要让它成为静态的。
  • interface 中拥有static 成员是没有意义的。为什么不能使用QueryBuilder.GetSqlClause 而不是IQueryBuilder.GetSqlClause
  • 旁注:将System.List&lt;IDataParameter&gt; 作为ref 参数传递是一个糟糕的设计。定期传递,甚至更好,如IList&lt;IDataParameter&gt;
  • @Jaylen,我曾经想知道这一点。我的问题是我不理解接口的意义。您应该阅读测试驱动设计和依赖注入。

标签: c#


【解决方案1】:

如果您希望您的方法是静态的并且实现一个接口,该语言不会让您这样做,但您可以通过多种方式解决它:

  • 如果从静态上下文访问整个实现有意义,您可以简单地声明一个单例对象:

    public static QueryBuilder Instance { get; } = new QueryBuilder();
    

    现在您可以访问QueryBuilder.Instance 静态属性,其值实现IQueryBuilder

  • 通过显式方法实现。这是实现接口方法的附加实例方法,其签名不会与类中的其他方法冲突。

    string IQueryBuilder.GetSqlClause(List<IReportFilter> reportFilters, ref List<IDataParameter> sqlParams)
    {
        // Call the static method, this is *not* a recursive call
        return GetSqlClause(reportFilters, ref sqlParams);
    }
    

    显式实现的一般语法是:

    ReturnType InterfaceName.MethodName(ParamType param)
    {
        ...
    }
    
  • 另一种(更简单的)解决方案是使用两个不同的方法名称。

【讨论】:

  • 那还是一个实例方法;它不是静态的。
  • @Servy 是的,实例方法调用静态方法。这以我理解的方式回答了这个问题。
  • @Servy 我重写了答案,希望能更清楚地说明我的观点,现在更好了吗?尽管设计可能存在问题,但它在某些情况下可能会被证明是有用的。
【解决方案2】:

C# 不支持实现接口方法的静态成员。

【讨论】:

  • 没错,但 StackOverflow 不是一个琐事游戏。接口中的静态成员甚至没有意义,但根据您的回答,OP 可能会认为它只是不受支持
猜你喜欢
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 2012-03-13
  • 1970-01-01
  • 2012-02-11
相关资源
最近更新 更多