Soru Neden C # yöntemlerini sanal ve statik olarak bildiremiyorum?


Sadece bir grup statik yöntem olan ve yardımcı sınıfı alt sınıflamak isteyen bir yardımcı sınıfım var. Bazı davranışlar alt sınıfına bağlı olarak benzersizdir, bu yüzden temel sınıftan sanal bir yöntem aramak istiyorum, ancak tüm yöntemler statik olduğundan, sanal bir yönteme (sanal yönteme erişmek için nesne başvurusu gerekir) oluşturamıyorum.

Bunun etrafında bir yolu var mı? Sanırım bir tek kişilik kullanabilirim .. HelperClass.Instance.HelperMethod () HelperClass.HelperMethod () 'dan çok daha kötü değil. Brownie, sanal statik yöntemleri destekleyen bazı dilleri işaret eden herkese işaret ediyor.

Düzenle: Tamam evet çıldırıyorum Google arama sonuçları bana biraz orada olmadığımı düşünüyordu.


44
2017-10-29 20:17


Menşei


Bu tarz bir senaryo, muhtemelen bunu nesneye dönüştürmeniz anlamına gelir (singletons değil). - yfeldblum
Her ne kadar bu yardımcı yöntem her yerde kullanılıyorsa bir nesneyi başlatmak zorunda kalmak istemiyorum. - Luke
Daha sonra, hangisinin mantıklı olduğuna bağlı olarak, bir tek veya bağımlılık enjeksiyonu kullanın. - Chris Marasti-Georg
Olası kopya Neden C # 'de soyut statik yöntemler kullanamıyorum? - Ken Kin
Olası kopya Sanal statik özellikler nasıl uygulanır? - peterh


Cevaplar:


Sanal statik yöntemler anlamlı değildir. Eğer ararsam HelperClass.HelperMethod();neden bazı rastgele alt sınıf yöntemlerinin çağrılmasını beklerim? 2 alt sınıfınız olduğunda çözüm gerçekten bozulur HelperClass - hangisini kullanırdınız?

Aşınabilir statik tipli yöntemlere sahip olmak istiyorsanız, muhtemelen şunları yapmalısınız:

  • Aynı alt sınıfın global olarak kullanılmasını istiyorsanız, bir singleton.
  • Uygulamanızın farklı bölümlerinde farklı davranışlar istiyorsanız, fabrika veya bağımlılık enjeksiyonlu bir gelenek sınıfı hiyerarşisi.

Durumunuzda hangi çözümün daha anlamlı olduğunu seçin.


43
2017-10-29 20:21



-1 Çünkü jenerikleri unuttun. T.Add (leftT, rightT); bu kadar mantıklı. Öyle değil mi? - SeeR
Uygulamanızı bir alt sınıfta nasıl geçersiz kılarsınız? - Chris Marasti-Georg
Sınıfın bir sanal örnek üyesi olarak uygulanabilir. Alt sınıfların türleri, sınıf türünden miras alır ve onları geçersiz kılar. - Craig Gidney
Evet, ancak alt sınıfın uygulaması, temel sorudan asıl sorulan soru olan statik bir bağlamda mevcut olmayacaktır. - Chris Marasti-Georg
Evet, mantıklılar, sadece semantik meselesi. Bir sınıf içinde statik bir metot beyan etmenin mantıklı olduğunu düşünürsek, bu durumun, her bir tip için de geçersiz kılınmasının mantıklı olduğunu söyleyebilirim. Bu konudaki Delphi örneklerine bakın. 'Statik' tanımlanmış bir anlama sahip olduğunu iddia edebilirsiniz; iyi, C, örneğin C # ve Java'dan çok farklı bir anlama sahiptir. - etrusco


Ben deli olduğunu düşünmüyorum. Sadece şu anda .NET'te imkansız olanı kullanmak istiyorsunuz.

Jenerikler hakkında konuşuyorsak, sanal statik yöntem talebiniz çok mantıklı olurdu. Örneğin, CLR tasarımcıları için gelecekteki isteğim, aşağıdaki gibi bir ara yazmamı sağlamaktır:

public interface ISumable<T>
{
  static T Add(T left, T right);
}

ve bunu şöyle kullanın:

public T Aggregate<T>(T left, T right) where T : ISumable<T>
{
  return T.Add(left, right);
}

Ama şu anda imkansız, bu yüzden böyle yapıyorum:

    public static class Static<T> where T : new()
    {
      public static T Value = new T();
    }

    public interface ISumable<T>
    {
      T Add(T left, T right);
    }

    public T Aggregate<T>(T left, T right) where T : ISumable<T>, new()
    {
      return Static<T>.Value.Add(left, right);
    }

29
2018-03-10 23:31



@SeeR: -1: Eğer yanılıyorsam düzelteceğim, fakat bu orijinal problemi çözmüyor. - John Saunders
@John Saunders: Statik sanal yöntemler istiyor ama imkansız - Bunun için örnek yöntemleri kullanması gerekiyor. Ayrıca bu sınıfı (şimdiki örneği) kullanmak istediği her zaman bu sınıfı oluşturmak istemiyor - bu yüzden Static <T> sınıfını yarattım. Artık tüm uygulama için sınıfının sadece bir örneğini alacaktır. Bu işlevsellik için kabul edilebilir bir vergi olduğunu düşünüyorum. Agrega <T> yöntemi, onu nasıl kullanabileceğinin sadece bir örneğidir. Özetle, c # 'de statik sanal yedek var - söz konusu talep değildi? - SeeR
@SeeR: Söz konusu tür bir new kısıtlama. Statik sanal yöntemler, bu tür yapıların, güvenliğini sağlamayan türlerle güvenli bir şekilde kullanılmasına izin verir. new kısıtlama. Alternatif olarak, biri olabilir Static sınıf yok new Kısıtlama, özel bir parametreli yapıcı ile bir nesne oluşturmak için Yansıma'yı kullanmayı dener. Ne yazık ki, bu tip güvenli hale getirmek için herhangi bir yol bilmiyorum. - supercat


Gerçekten, bu Delphi'de yapılabilir. Bir örnek:

type
  TForm1 = class(TForm)
    procedure FormShow(Sender: TObject);
  end;

  TTestClass = class
  public
    class procedure TestMethod(); virtual;
  end;

  TTestDerivedClass = class(TTestClass)
  public
    class procedure TestMethod(); override;
  end;

  TTestMetaClass = class of TTestClass;

var
  Form1: TForm1;

implementation

{$R *.dfm}

class procedure TTestClass.TestMethod();
begin
  Application.MessageBox('base', 'Message');
end;

class procedure TTestDerivedClass.TestMethod();
begin
  Application.MessageBox('descendant', 'Message');
end;


procedure TForm1.FormShow(Sender: TObject);
var
  sample: TTestMetaClass;
begin
  sample := TTestClass;
  sample.TestMethod;
  sample := TTestDerivedClass;
  sample.TestMethod;
end;

Oldukça ilginç. Artık Delphi kullanmıyorum, ancak metaclass özelliğini kullanarak özel bir tasarımcı tuvalinde farklı kontrol tipleri oluşturabildiğinizi hatırlıyorum: kontrol sınıfı, örn. TButton, TTextBox vb. Bir parametredir ve gerçek metaclass argümanını kullanarak uygun kurucuyu arayabilirim.

Fakir adamın fabrika modelinin türü :)


13
2017-10-29 20:46



C # statik sanal yöntemleri desteklememesi beni çıldırtıyor ... özellikle de c # 'nin 10 yıl önce delphi tasarlayan aynı kişi tarafından tasarlandığı düşünülüyor (Anders Hejlsberg) - Carlo Sirna


Aynı etkiyi sadece normal bir statik yöntemle elde edip daha sonra new anahtar kelime

public class Base 
{
    //Other stuff

    public static void DoSomething()
    {
        Console.WriteLine("Base");
    }
}

public class SomeClass : Base
{
    public new static void DoSomething()
    {
        Console.WriteLine("SomeClass");
    }
}
public class SomeOtherClass : Base
{
}

Öyleyse böyle yöntemleri arayabilirsin.

Base.DoSomething(); //Base
SomeClass.DoSomething(); //SomeClass
SomeOtherClass.DoSomething(); //Base

11
2017-08-22 20:00



Bunun istenmeyen sonuçları olabilir. Örneğin, eğer temel sınıfınızda, DoSomething'i çağıran başka bir yönteminiz varsa ve siz de SomeClass.ThatOtherMethod () yöntemini çağırıyorsanız, bu yöntem bazanın DoSomething öğesini çağırır, SomeClass'ın sürümünü değil. dotnetfiddle.net/scRWKD - user420667
Hiçbir şeyin bu şekilde yapılmadığından emin olmak için temel sınıfta NotImplementedException öğesini atayın - Rob Sedgwick


Ben Delphi gelen ve bu c # içinde özledim birçok arasında bir özellik. Delphi, yazdığınız tipte referanslar oluşturmanıza izin verir ve bir ana sınıfın türüne ihtiyaç duyulduğunda türetilmiş bir sınıfın türünü geçirebilirsiniz. Bu tür nesnelerin nesneler olarak muamelesi güçlü bir faydaya sahipti. Özellikle meta verilerinin çalışma süresi tayinine izin verilmesi. Buradaki sözdizimini karıştırıyorum ama c # gibi bir şeye benziyordu:

    class Root {
       public static virtual string TestMethod() {return "Root"; }
    }
    TRootClass = class of TRoot; // Here is the typed type declaration

    class Derived : Root {
       public static overide string TestMethod(){ return "derived"; }
    }

   class Test {
        public static string Run(){
           TRootClass rc;
           rc = Root;
           Test(rc);
           rc = Derived();
           Test(rc);
        }
        public static Test(TRootClass AClass){
           string str = AClass.TestMethod();
           Console.WriteLine(str);
        }
    } 

üretmek:   Kök   türetilmiş


8
2017-07-06 18:00





bir sınıf örneğinin dışında bir statik yöntem var. Statik olmayan verileri kullanamaz.

sanal bir yöntem, aşırı yüklü bir fonksiyon tarafından "üzerine yazılır" tip bir örneğinin

böylece statik ve sanal arasında açık bir çelişki var.

Bu bir destek sorunu değil, bir kavramdır.

Güncelleştirme: Burada yanlış olduğumu kanıtladım (yorumlara bakın):

Bu yüzden sanal destek olacak herhangi bir OOP-Dilini bulacağınızdan şüpheliyim.   statik yöntemler.


7
2017-10-29 20:21



Örneğin türü üzerinde sanal bir yöntemin üzerine yazılabilir. Tüm alt sınıflar aşırı yüklenmiş fonksiyonun aynı uygulamasını paylaşabilir. Bu yüzden onları çok statik ve sanal yapmak istersiniz. Bu, PHP5'te mevcut olan, geç statik bağlantıdır. - Alex Weinstein
Hayır, çelişki yoktur, tamamen bir derleyici desteği meselesidir ve Python gibi birçok dil bunu yapar. Bunu birinci sınıf sınıfları yaparak yaparlar. Yani, değişkenlere atanabilen ve yöntemlerinin çağrıldığı nesneler olan sınıflardır. (Daha fazla bilgi için "classmethod" araması yapın.) - Daniel Newby
Object Pascal (Delphi ve açık kaynak Lazarus muadili) her zaman onları destekledi - Carlo Sirna


Sen deli değilsin. Ne atıfta bulunursan Geç Statik Bağlama denir; son zamanlarda PHP'ye eklendi. Bunu açıklayan harika bir iş parçacığı var - burada: Geç statik bağlanmayı ne zaman kullanmanız gerekir?


6
2017-10-30 19:45





Mart, 'yeni' anahtar kelimeyle haklı çıktı. Aslında buradayım çünkü bu tür bir işleve ihtiyacım vardı ve Mart'ın çözümü iyi çalışıyor. Aslında bunu daha iyi kullandım ve programcılığı bu alana sunmaya zorlamak için temel sınıf yöntemimi soyutlaştırdım.

Benim senaryo şu şekilde oldu:

HouseDeed bir temel sınıfım var. Her Ev tipi HouseDeed'den türetilmiş bir fiyat olmalıdır.

İşte kısmi temel HouseDeed sınıfı:

public abstract class HouseDeed : Item
{
    public static int m_price = 0;
    public abstract int Price { get; }
    /* more impl here */
}

Şimdi iki tür ev tipine bakalım:

public class FieldStoneHouseDeed : HouseDeed
{
    public static new int m_price = 43800;
    public override int Price { get { return m_price; } }
    /* more impl here */
}

ve...

public class SmallTowerDeed : HouseDeed
{
    public static new int m_price = 88500;
    public override int Price { get { return m_price; } }
    /* more impl here */
}

Gördüğünüz gibi evin fiyatına SmallTowerDeed.m_price ve yeni SmallTowerDeed (). Özet olarak, bu mekanizma programcıyı her yeni türetilmiş ev tipi için bir fiyat sağlamaya zorluyor.

Birisi 'statik sanal' ve 'sanal' kavramlarının kavramsal olarak birbirleriyle nasıl çeliştiğine işaret etti. Katılmıyorum. Bu örnekte, statik yöntemlerin örnek verisine erişmesi gerekmez ve bu nedenle (1) fiyatın yalnızca TYPE üzerinden kullanılabilir olması ve (2) bir fiyatın karşılanması gerekir.


2
2018-05-30 16:44



Bu cevap sadece soruyla teğetsel olarak ilişkili görünüyor. Ayrıca bu biraz zayıf bir örnektir. m_price bir uygulama detayıdır ve HouseDeed'in bir parçası olarak hiçbir şey eklemez. HouseDeed'ten kaldırmak ve her iki alt sınıfta m_price özel yapmak çok daha iyi olurdu. 'New' anahtar kelimesinin kötüye kullanımı olmadan aynı sonuç. - Rob McCready