20

Is it possible in C# to extend a class not by adding only functions but properties. Ex: i have a standard DLL library I am relying on and the vendor does not want to modify it.

Already throughout the code I have used the DataCell class extensively and only now realized that I need to add an extra property to it, as creating a new extension class that inherits from this class just does not look like it would work + a lot of rewriting.

DataCell [metadata]

public class DataCell : Message
{
public int Field1;
public int Field2;
public DataCell()
{
 ..
} 
..
}

Basically I want to add a public int Flags; to this class. So I can do now without rewriting anything, (new DataCell).Flags = 0x10;

wonea
  • 4,783
  • 17
  • 86
  • 139
Vans S
  • 1,743
  • 3
  • 21
  • 36
  • 1
    You can't have extension properties but you can inherit a class and add properties – Sayse Jul 12 '13 at 13:40
  • What do you mean by "extend" in this case? Do you have the source code? Or do you want to use an extension property (which you can't)? or is inheriting from DataCell ok? – Tim Jul 12 '13 at 13:41
  • By extend I mean this class is heavily used in the vendors .dll lib that I am using. creating like ExtDataCell : DataCell is not an option as I would basically need to rewrite the .dll lib. So I want to somehow be able to do it so DataCell from the vendors .dll can have the property Flags which it does not have atm. (without modifying the vendor dll) – Vans S Jul 12 '13 at 13:45

3 Answers3

19

First of all, you should probably reconsider your approach. But if all else fails, here is how you can sort of add a property to a sealed class:

using System;
using System.Runtime.CompilerServices;

namespace DataCellExtender
{

    #region sample 3rd party class
    public class DataCell
    {
        public int Field1;
        public int Field2;
    }
    #endregion

    public static class DataCellExtension
    {
        //ConditionalWeakTable is available in .NET 4.0+
        //if you use an older .NET, you have to create your own CWT implementation (good luck with that!)
        static readonly ConditionalWeakTable<DataCell, IntObject> Flags = new ConditionalWeakTable<DataCell, IntObject>();

        public static int GetFlags(this DataCell dataCell) { return Flags.GetOrCreateValue(dataCell).Value; }

        public static void SetFlags(this DataCell dataCell, int newFlags) { Flags.GetOrCreateValue(dataCell).Value = newFlags; }

        class IntObject
        {
            public int Value;
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            var dc = new DataCell();
            dc.SetFlags(42);
            var flags = dc.GetFlags();
            Console.WriteLine(flags);
        }
    }
}

Please don't do this unless you really must. Future maintainers of this code may have some strong words for you if there's a cleaner solution that you skipped in favor of this slightly hacky approach.

dss539
  • 6,804
  • 2
  • 34
  • 64
  • 2
    That's definitely an interesting workaround. I would explore cleaner options first, but it's worth considering at least. – Jon Skeet Jul 12 '13 at 15:04
  • 1
    @JonSkeet Ah yes, I forgot to explicitly mention how awful this is and that it shouldn't be done. I'll edit that in. – dss539 Jul 12 '13 at 15:06
  • Wow this question hit 10k views. Accepted this as best answer as this seems to be what I needed back then. Not sure on performance tho. – Vans S Jun 16 '15 at 04:58
  • +100 the gist of it is that if you store a reference to an object as a key in the `ConditionalWeakTable`, then that entry gets removed if all instances of the object are deleted elsewhere. This allows us to associate metadata with the sealed class, making it appear that the metadata is part of the class, but not have to deal with the complexities of removing that metadata after it's deleted elsewhere. https://docs.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.conditionalweaktable-2 and more info at https://stackoverflow.com/questions/18465630/understanding-conditionalweaktable – Zack Morris Sep 12 '19 at 21:36
  • 1
    @ZackMorris yep. You can keep some data on behalf of other objects. You can access the data via extension methods. You can erase the data "magically" by deleting the related object. It's hacky but it works. :) I don't think Mr. Belding would approve though. – dss539 Sep 12 '19 at 21:48
  • Thanks, it worked for me with slight modification for the Generic Types (Node<>, etc), by adding the dynamic keyword: private static readonly ConditionalWeakTable Heights = new ConditionalWeakTable(); – vCillusion May 31 '20 at 08:34
9

Well you can certainly extend a class and only add fields/properties to it (although I'd discourage the use of public fields as per your sample). However, unless other code uses your new class, the fields won't exist in the objects created. For example, if other code has:

DataCell cell = new DataCell();

then that won't have your Field1 and Field2 fields.

If every instance of the base class really should have these fields, you'd be better off working out how to change the base class rather than extending it.

If you were wondering whether you could add "extension fields" in the same way as extension methods are added (e.g. public static void Foo(this DataCell cell)) then no, that's not possible.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • The problem is this class is used extensively in another class supplied by the vendor. So extending the class per inheritance, would need to extend a bunch of other classes and rewrite a lot. ok thanks – Vans S Jul 12 '13 at 13:42
  • @VansS: Well it's still unclear to me whether basically the base class should have the extra fields, or who owns the base class. But you can't just add fields to classes you don't own. – Jon Skeet Jul 12 '13 at 13:51
5

There are two ways to add properties to an existing class

  1. Add partial class, but this won't work for you because partial classes should be in the same assembly.

  2. Inherit this class in a different class which as far I know would be a better solution for you.

And no you can't use a extension property like an extension method.

jonni
  • 338
  • 1
  • 13