具有相同参数签名的C#构造函数

具有相同参数签名的C#构造函数,c#,.net,C#,.net,我相信这一定是一个常见的问题。我有一个类,在理想情况下,它会有以下构造函数 public Thing(string connectionString) public Thing(string fileName) 显然这是不允许的,因为签名是相同的。有人知道这个问题的优雅解决方案吗 创建两个公共属性ConnectionString和FileName,然后使用它们填充对象 在C#中,可以使用对象初始化器。像这样: Thing thing = new Thing{FileName = "abc",

我相信这一定是一个常见的问题。我有一个类,在理想情况下,它会有以下构造函数

public Thing(string connectionString)

public Thing(string fileName)

显然这是不允许的,因为签名是相同的。有人知道这个问题的优雅解决方案吗

创建两个公共属性ConnectionString和FileName,然后使用它们填充对象

在C#中,可以使用对象初始化器。像这样:

Thing thing = new Thing{FileName = "abc", ConnectionString = "123"};

您可以使用命名构造函数习惯用法:

public class Thing
{
    private string connectionString;

    private string filename;

    private Thing()
    {
        /* Make this private to clear things up */
    }

    public static Thing WithConnection(string connectionString)
    {
        var thing = new Thing();
        thing.connectionString = connectionString;
        return thing;
    }

    public static Thing WithFilename(string filename)
    {
        var thing = new Thing();
        thing.filename = filename;
        return thing;
    }
}

您可以将所有构造函数设置为私有并创建工厂方法(类上的静态方法,如CreateFromConnectionString())。

以下是一些解决方法

有一个接受连接字符串的构造函数,然后在接受filename的类上有一个工厂方法。大概是这样的:

public static Thing CreateThing(string fileName)
这个方法可以调用一个私有的无参数构造函数,您可以从那里获取它


另一种选择是拥有一个包含两种类型的枚举。文件名和连接字符串。然后只需要一个接受字符串的构造函数和枚举。然后,根据枚举,您可以确定要走哪条路。

对我来说,这些实际上看起来像是不同的“东西”,或者是与文件关联的类,或者是与数据库关联的类。我会定义一个接口,然后为每个接口分别实现。使用工厂生成正确的实现

您可能需要更改设计的一个提示是,如果您的方法在执行所需操作之前必须决定是使用文件还是使用数据库。如果是这样的话,那么我会选择分门别类

public interface IThing
{
   ... methods to do the things that Things do
}

public class FileThing : IThing
{
  ... file-based methods
}

public class DatabaseThing : IThing
{
  ... database-based methods
}

public static class ThingFactory
{
     public IThing GetFileThing( string name )
     {
         return new FileThing( name );
     }

     public IThing GetDatabaseThing( string connectionString )
     {
         return new DatabaseThing( connectionString );
     }
}

如果您有公共行为,您也可以定义一个包含默认/公共行为的抽象类,并从中派生,而不是/除了接口。

我喜欢静态构造函数:

class Thing
{
   public static Thing NewConnection(string connectionString)
   {
       return new Thing(connectionString, true);
   }

   public static Thing NewFile(string fileName);
   {
        return new Thing(fileName, false);
   }
}
.
.
.
{
    var myObj = Thing.NewConnection("connect=foo");
    var Obj2 = Thing.NewFile("myFile.txt");
}

(未显示,但直截了当地说,是带有一个额外布尔参数的Thing构造函数的实现)。

好吧,有几种可能性-什么是elegent取决于使用场景

  • 静态工厂方法,调用私有构造函数

    static Thing thingWithFileName(string fileName)
    
  • 为其中一个参数创建其他类型,或使用内置参数。您可以使用System.IO.FileStream,而不是字符串文件名。这也是更安全的类型,因为我不能意外地将错误的数据传递到错误的静态方法或字段中

  • 将第二个参数(枚举或布尔)传递给构造函数,指示第一个参数的意图

    enum ThingType { FileName, ConnectionString }
    Thing(string str, ThingType type) ...
    
  • 子类的东西,所以你有一个ConnectionTypeThing和一个FileBackedThing

  • 完全消除连接,并提供预连接的数据源。所以你最终得到了

    Thing(InputStream dataSource)
    
    或者类似的东西


我的“优雅”钱来自第一个或第二个建议,但我需要更多的背景来满足任何选择。

降低分数有什么用?这是一个有效的用例。在这一场景中,它有一些问题,因为它没有使设置两者的非法性变得显而易见,但它几乎没有完全的缺陷。我没有投票否决这一点,但是我也不会建议这样做。通常,在构建对象之后,您希望对其进行“设置”。这样您就知道,一旦对它调用了方法,它就已经处于您期望的特定状态。虽然这也是我最初采用的方法,但使用工厂方法,我关心的是一种试图将基于文件的访问和数据库访问封装在一个类中的设计。我也有同样的想法,但后来我意识到“connectionString”可能不是指数据库连接,而是指基于文件的连接。我同意,如果
东西
在执行双重任务,它可能应该被划分为不同的类。@sean--仍然可疑,通常我会认为是基于文件的连接的文件名或路径。对于基于文件的数据库,您可以始终只提供正确的连接字符串。在此基础上的一个微小变化是创建一个名为“Factory”的嵌套类型,其中包含这些方法,因此您可以编写“Thing.Factory.CreateWithConnection()”。工厂类型可以访问事物的私有属性。它有助于很好地分离关注点。@tvanfosson-对于类名“Thing”,我们只能推测它的实现。