【问题标题】:Does Generics give me some advantages in performance and pros and cons?泛型是否在性能和优缺点方面给了我一些优势?
【发布时间】:2012-10-26 13:14:17
【问题描述】:

我正在尝试生成如下所示的一些方法,添加crmhuman resources。但我想写 Crm、humanResources、SupplChain 等(5-6 个模块)如何简单地编写下面的代码(下面的代码是骨架:)) 我先写了没有泛型,然后我写了泛型。第二种用法与第一种不同。 1) 清晰的阅读也被管理和消耗
2)给我一些性能优势。没有装箱和拆箱过程

你能教我泛型的优缺点吗?比较第一次和第二次使用?


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace App.GenericsBaseClass.Diff
{

    // View : 
    class Program
    {
        static void Main(string[] args)
        {
            new Crm().Add("Yapı Kredi");
            Console.Read();
            new HumanResources().Add("yusuf karatoprak");
            Console.Read();
        }
    }

  // Business
    public class Crm : Customer
    {
        public override void Add(object obj)
        {
            if (obj is String)
            {
                base.Add(obj);
            }
            else
            {
                throw new InvalidOperationException("Customer Name must be string Format...");
            }
        }
    }

    public class HumanResources : Staff
    {
        public override void Add(object obj)
        {
            if (obj is string)
            {
                base.Add(obj);
            }
            else
            {
                throw new InvalidOperationException("Stuff Name must be string Format...");
            }

        }
    }

    // Dal
    public class Staff
    {
        public virtual void Add(object obj)
        {
            new Db.Staff().Save((string)obj);
        }
    }

    public class Customer
    {
        public virtual void Add(object obj)
        {
            new Db.Customer().Save((string)obj);
        }

    }
    // Model
    public class Db
    {

        public class Customer
        {
            public void Save(string Name)
            {
                Console.WriteLine("Customer : {0} is saved",Name);
            }
        }

        public class Staff
        {
            public void Save(string Name)
            {
                Console.WriteLine("Staff: {0} is saved", Name);
            }
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace App.GenericsInstadofBaseMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            new Crm<string>().Add("Yapı Kredi");
            Console.Read();
            new HumanResources<string>().Add("yusuf karatoprak");
            Console.Read();
        }
    }

    // Business
    public class Crm<T> : Customer<T>
    {
        public override void Add(T obj)
        {
                base.Add(obj);
        }
    }

    public class HumanResources<T> : Staff<T>
    {
        public override void Add(T obj)
        {
                base.Add(obj);
        }
    }

    // Dal
    public class Staff<T>
    {
        public virtual void Add(T obj)
        {
            new Db<T>.Staff().Save(obj);
        }
    }

    public class Customer<T>
    {
        public virtual void Add(T obj)
        {
            new Db<T>.Customer().Save(obj);
        }

    }
    // Model

    public class Db<T> 
    {
        public class Customer
        {
            public void Save(T Name)
            {
                Console.WriteLine("Customer : {0} is saved", Name.ToString());
            }
        }

        public class Staff
        {
            public void Save(T Name)
            {
                Console.WriteLine("Staff: {0} is saved", Name);
            }
        }

    }
}

【问题讨论】:

  • 你想通过使用泛型来实现什么?拥有通用的Name 对我来说似乎毫无用处。
  • 应该是Customer&lt;T&gt;Staff&lt;T&gt; 而不是Db&lt;T&gt;
  • 如果你想保存一个字符串名称,让你的方法接受一个字符串。创建一个您实际上无法履行的 API 合同有什么意义?由于持久性问题与不必要的深继承层次结构的混合,整个类型层次结构混乱。我建议看看一个不错的 ORM。

标签: c# .net generics architecture


【解决方案1】:

据我所知,大多数泛型操作都发生在IL 级别,因此不会对性能造成太大影响(如果有的话)。它所做的只是强制并检查对象是否属于某种类型。最大的缺点是对逆变和协变的理解。这里有一些关于它的文章。

文章

Using Variance in Interfaces for Generic Collections

Covariance and Contravariance FAQ (.NET 4.0 Updated)

优点

使用泛型,您可以在运行时和设计时都获得类型安全。您可以实时接收有关对象的智能感知,就好像它们是针对特定类型进行硬编码一样。这在设置两种扩展方法时非常有用,而且……几乎所有其他东西。事实上,从 .NET 2.0 开始,我什至不再使用非泛型列表来处理任何事情,除非类型只是 object

  • 编辑

正如其他人指出的那样,这可以防止拆箱。

缺点

由于逆变和协变的不同性质,有时可能会混淆泛型中什么是可接受的,什么是不可接受的。例如,如果您考虑以下布局..

interface IBase {
}

class Alpha : IBase {
}

class Beta : Alpha {
}

IList<IBase> ListOfObjects { get; set; }

这令人困惑。您可以将AlphaBeta 对象都传递到列表中吗?当我尝试它时,你不能。但随后以下工作..

IList<Alpha> ListOfObjects { get; set; }

它同时接受AlphaBeta 对象,因为Beta 继承Alpha

看看更多关于逆变和协方差的信息here。很有用。

从未注意到泛型对性能的影响。然而,这并不意味着它们不存在。但是它们只是普通的对象,所以我看不出哪里会有开销。一般来说,编译器甚至不应该让您在尝试将不正确的对象添加到通用列表的地方运行代码,如果确实如此,那么您在某处犯了设计错误,或者正在使用dynamics,或者遇到逆变与协方差的问题。虽然我确实明白其中一些已经随着 .NET 4.0 发生了变化。

【讨论】:

  • 实际上并不完全类似于模板。 “旧 C++ 代码”是什么意思?
  • 术语差异。我的大学教授向我们展示了 C++ 中的一些东西,很久以前它的功能与泛型有点相似,并将它们称为模板。我不会用 C++ 编写代码,所以我不知道实际的术语。我应该更具体一点——老实说,我什至不记得它足以理解为什么我把那个评论放在那里。基本上,您可以建立一个可以接受任何类型的类并对它们执行某些操作,而不管类型如何。
【解决方案2】:

除了我的帖子解释了一些关于泛型的事情之外,你在这里的情况看起来根本不需要它们。您应该改为向您的类添加一个属性。

public class Person {
   public string Name { get; set; }
}
public class Customer : Person {

}
public class Staff : Person {
}

public class HumanResources : Staff {
}

public class Db {
  public List<Customer> Customers { get; set; }
  public List<Staff> Staff { get; set; }
}

public static void Main(){ 
  var db = new Db {
     Customers = new List<Customer> { },
     Staff = new List<Staff> { }
  };

  Db.Customers.Add(new Customer { Name = "Primary Customer" } );
  Db.Staff.Add(new Staff { Name = "Employee Prime" } );
  Db.Staff.Add(new HumanResources { Name = "Human Resource Manager" });
}

应该使用泛型来坚持输入的类型,而不是实际控制数据。您所拥有的示例并未以其真正的预期方式使用泛型。

在此示例中,您创建了一个基类,然后创建了三个子类型,其中一个继承自另一个子类型。所以你有CustomerStaff 作为Db(假设是数据库的缩写)接受的两种主要类型。

Db 可以获取Customers 列表和Staff 列表,因为HumanResourcesStaff 的一种类型,您可以将它们存储在一起。您还可以添加List&lt;Person&gt; People { get; set; },它会接受所有类型,因为它们不可避免地会相互继承。

至于强制字符串,最好在你的构造函数中完成。

public class Person { 
   public Person(string name) { 
      this.Name = name; }
   }

   public string Name { get; private set; }
}

在这个例子中,我们设置了 Name 字段,以便所有东西都可以看到它,但只是在创建时更改和设置(这不是最好的想法,但它证明了这一点)。

所以现在,你可以像这样添加一个新的Customer ..

Db.Customers.Add( new Customer ( "Ciel" ) ); 或新员工...Db.Staff.Add( new Staff( "Darin" ) );

【讨论】:

    【解决方案3】:

    我认为性能差异并不显着。

    使用泛型真正获得的是类型的编译时检查。例如,它可以防止您传递错误类型的对象(如果您需要特定类型,则在这种情况下使用 object 参数会导致运行时错误)。

    【讨论】:

    • 泛型允许您避免对值类型进行装箱,而使用 object 会强制装箱。
    • 我将补充一点,泛型在编译时创建方法的静态版本,而不是运行时。所以应该不会对性能产生任何影响。
    【解决方案4】:

    泛型是关于类型安全恕我直言。你可以编写更健壮的代码,因为你得到的是编译时错误而不是运行时试错。

    装箱是一种奖励,但您不应该仅仅为了避免装箱而选择泛型(这听起来像是过早的优化)。

    【讨论】:

      【解决方案5】:

      您可以在这里找到Advantages and Disadvantages of using generics 上的一个非常有趣的视频。

      【讨论】:

        猜你喜欢
        • 2010-09-12
        • 2011-12-18
        • 2017-04-14
        • 2012-01-11
        • 2018-10-26
        • 1970-01-01
        • 2011-04-02
        • 2015-09-26
        • 2010-10-20
        相关资源
        最近更新 更多