在扩展方法中实例化Null对象

时间:2011-04-02 13:22:17

标签: c# .net-3.5

我想知道是否可以在该对象的扩展方法中实例化一个空对象。

示例:

简单课程

public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}

扩展方法

public static class ExtensionMethods
{
    public static void GetTestClass(this TestClass tc, string name)
    {
        using (SqlConnection cn = new SqlConnection(myConnectionString))
        using (SqlCommand cmd = cn.CreateCommand())
        {
             cmd.CommandText= "SELECT Name, Age FROM Person WHERE Name = @Name";
             cn.Open();

             cmd.Parameters.AddWithValue("@Name", name);

             using (SqlDataReader dr = cmd.ExecuteReader())
             {
                 if (dr.Read())
                 {
                     tc = new TestClass();
                     tc.Name = name;
                     tc.Age = int.Parse(dr["Age"]);
                 }
             }
        }
    }
}

用户将给我一个名字,我想通过这样做验证该名称是否存在......

static void Main(string[] args)
{
    TestClass tc = null;
    tc.GetTestClass("Some Name");

    if (tc == null)
    {
        Console.WriteLine("Not Found");
    }

    Console.Read();
}

这可能吗?我当前的代码将原始对​​象保留为null。我不知道我做错了什么,这是不可能的。

感谢。

6 个答案:

答案 0 :(得分:3)

这不起作用,您需要一个返回对象的方法。在扩展方法中分配 this 参数将不会执行您希望它执行的操作,也不会修改tc变量。

您可能会成为IntelliSense陷阱的牺牲品,是的,它会向您展示GetTestClass()方法。但是你必须编写的代码没有通过右侧代码审查门:

  tc = tc.GetTestClass("some name");

显然,您需要一个静态工厂方法:

  tc = Mumble.CreateTest("some name");

答案 1 :(得分:2)

我同意@Stuart。看起来您希望扩展方法将使用数据库检索的内容覆盖类的当前实例。

您需要删除读取循环中的tc = new TestClass();或将此扩展类重写为TestClass上的静态工厂方法,或者可能是TestClassFactory

答案 2 :(得分:1)

不 - 这段代码没有意义:

TestClass tc = null;
tc.GetTestClass("Some Name");

这可能看起来应该抛出NullReferenceException ...

好的 - 所以它没有(请参阅http://www.pvle.be/2008/11/extension-methods-and-null-objects/上的示例)但它也没有通过ref传递tc ...因此它不会更新tc为你


关于扩展程序的MSDN说:

  

一般情况下,我们建议你   谨慎地实施扩展方法   只有当你必须。每当   可能的,必须扩展的客户端代码   现有类型应该通过   创建一个派生自的新类型   现有的类型。

http://msdn.microsoft.com/en-us/library/bb383977.aspx


IMO最好将你正在寻找的东西作为某种工厂方法来实现。

或者你可以使用类似的东西:

   TestClass tc = new TestClass();
   if (tc.TryFillFrom("Some Name"))
   {
       // do stuff
   }
   else
   {
       // handle missing error
   }

或者你可以使用FillFrom方法抛出一些NotFoundException

答案 3 :(得分:1)

这是可能的,但是当您分配给tc时,赋值仅影响方法内的参数,而不影响传递给该参数的变量。它与传统参数传递的情况没有什么不同:

public static void GetTestClass(TestClass tc, string name) {
    ...
    tc = new TestClass();
    ...
}

static void Main() {
    TestClass tc = null;
    GetTestClass(tc, "Some Name");
    // The assignment to tc in GetTestClass doesn't affect the tc variable in Main.
    ...
}

至于解决方案,请避免在空引用上调用扩展方法。这显然令人困惑。只需通过更简单,更传统的习语来获取新对象:

public static TestClass GetTestClass(string name) {
    ...
    TestClass tc = new TestClass();
    ...
    return tc;
}

static void Main() {
    TestClass tc = GetTestClass("Some Name");
    ...
}

答案 4 :(得分:1)

不,这是不可能的。

它只是发送到方法的变量的引用副本,因此您无法更改变量的内容。

无论如何,使用这样的扩展方法并不直观。虽然你可以在空引用上调用扩展方法,但是你的方法依赖它。

只需使用常规静态方法,如果找不到记录,则返回null:

TestClass tc = TestClass.GetTestClass("Some Name");

答案 5 :(得分:0)

我很惊讶每个人都提供静态方法解决方案。如果这是您的类始终实例化的方式,请使用构造函数。这就是他们的目的。如果它不是唯一的方法,那么创建一个空的构造函数并重载它以传递您的参数,当您希望它以这种方式实例化时。我更喜欢这样的两个构造函数

public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }

    public TestClass() { }

    public TestClass(string name)
    {
        using (SqlConnection cn = new SqlConnection(myConnectionString))
        using (SqlCommand cmd = cn.CreateCommand())
        {
             cmd.CommandText= "SELECT Name, Age FROM Person WHERE Name = @Name";
             cn.Open();

             cmd.Parameters.AddWithValue("@Name", name);

             using (SqlDataReader dr = cmd.ExecuteReader())
             {
                 if (dr.Read())
                 {
                     Name = name;
                     Age = int.Parse(dr["Age"]);
                 }
             }
        }
    }
}

对我而言,这更为直截了当。当您无权访问类的代码以添加自己的方法时,应使用扩展方法。